Powershell脚本无法识别函数

Posted

技术标签:

【中文标题】Powershell脚本无法识别函数【英文标题】:Powershell script not recognising Functions 【发布时间】:2015-05-26 07:41:25 【问题描述】:

我编写了以下 PS 脚本来从特定服务器路径中删除日志文件。我是 PS 新手,但我在此脚本中编写的一些函数出现了一些错误:

#* FileName: FileCleaner.ps1
#Clear the screen
Clear

#Read XML Config File to get settings
[xml]$configfile = Get-Content "C:\Users\pmcma\Documents\Projects\Replace FileCleaner with PowerShell Script\FileCleaner.config.xml"

#Declare and set variables from Config values
$hostServer = $configfile.Settings.HostServer
$dirs = @($configfile.Settings.DirectoryName.Split(",").Trim())
$scanSubDirectories = $configfile.Settings.ScanSubDirectories
$deleteAllFiles = $configfile.Settings.deleteAllFiles
$fileTypesToDelete = @($configfile.Settings.FileTypesToDelete.Split(";").Trim())
$liveSiteLogs = $configfile.Settings.LiveSiteLogs
$fileExclusions = @($configfile.Settings.FileExclusions.Split(";").Trim())
$retentionPeriod = $configfile.Settings.RetentionPeriod
$AICLogs = $configfile.Settings.AICLogs
$AICLogsRententionPeriod = $configfile.Settings.AICLogsRententionPeriod
$fileCleanerLogs = $configfile.Settings.FileCleanerLogs
$fileCleanerLogsRententionPeriod = $configfile.Settings.FileCleanerLogsRententionPeriod

#Setup FileCleaner output success logfiles
$successLogfile = $configfile.Settings.SuccessOutputLogfile
$dirName  = [io.path]::GetDirectoryName($successLogfile)
$filename = [io.path]::GetFileNameWithoutExtension($successLogfile)
$ext = [io.path]::GetExtension($successLogfile)
$successLogfile = "$dirName\$filename$(get-date -Format yyyy-MM-dd)$ext"

#Setup FileCleaner output error logfiles
$errorLogfile = $configfile.Settings.ErrorOutputLogfile
$dirName  = [io.path]::GetDirectoryName($errorLogfile)
$filename = [io.path]::GetFileNameWithoutExtension($errorLogfile)
$ext = [io.path]::GetExtension($errorLogfile)
$errorLogfile = "$dirName\$filename$(get-date -Format yyyy-MM-dd)$ext"

#Setup Retention Period        
$LastWrite = (Get-Date).AddDays(-$retentionPeriod)#.ToString("d") 
$AICLastWrite = (Get-Date).AddDays(-$AICLogsRententionPeriod)#.ToString("d")
$fileCleanerLastWrite = (Get-Date).AddDays(-$fileCleanerLogsRententionPeriod)

#EMAIL SETTINGS
$smtpServer = $configfile.Settings.SMTPServer
$emailFrom = $configfile.Settings.EmailFrom
$emailTo = $configfile.Settings.EmailTo
$emailSubject = $configfile.Settings.EmailSubject
#Update the email subject to display the Host Server value
$emailSubject -replace "HostServer", $hostServer 

$countUnaccessibleUNCPaths = 0

#Check Logfiles exists, if not create them
if(!(Test-Path -Path $successLogfile))

    New-Item -Path $successLogfile –itemtype file


if(!(Test-Path -Path $errorLogfile))

    New-Item -Path $errorLogfile  –itemtype file


foreach ($dir in $dirs) 

#needs a check to determine if server/the UNC Path is accessible. If it fails to connect, it needs to move on to the next UNC share but a flag needs to 
#be generate to alert us to investigate why the UNC share was not accessible during the job run.
If(Test-Path -Path $dir)

    #write to output logfile Directory info
    $Msg = Write-Output "$(Get-Date -UFormat "%D / %T") - Accessing: $dir"
    $Msg | out-file $successLogfile

    If ($scanSubDirectories -eq "True") 
    
        If ($deleteAllFiles -eq "True") 
        
            #ScanSubDirectories and delete all files older than the $retentionPeriod, include Sub-Directories / also forces the deletion of any hidden files
            $logFiles = Get-ChildItem -Path $dir -Force -Recurse -Exclude $fileExclusions[0],$fileExclusions[1] | Where  $_.LastWriteTime -le "$LastWrite" 
            DeleteLogFiles($logFiles)
            #foreach($logFile in $logFiles)
            #
            #    if($logFile -ne $null)
            #    
            #        $Msg = Write-Output "$("Deleting File $logFile")" 
            #        $Msg | out-file $successLogfile -append 
            #        Remove-Item $logFile.FullName -Force
            #    
            #                                                             
         
        Else 
        
            #"ScanSubDirectories but only delete specified file types."
            $logFiles = Get-Childitem $dir -Include $fileTypesToDelete[0],$fileTypesToDelete[1],$fileTypesToDelete[2], $liveSiteLogs -Recurse -Exclude $fileExclusions[0],$fileExclusions[1] | Where $_.LastWriteTime -le "$LastWrite"
            DeleteLogFiles($logFiles)
            #foreach($logFile in $logFiles)
            #
            #    if($logFile -ne $null)
            #    
            #        $Msg = Write-Output "$("Deleting File $logFile")" 
            #        $Msg | out-file $successLogfile -append 
            #        Remove-Item $logFile.FullName -Force
            #    
            #  
           
     
    Else 
    
        #Only delete files in top level Directory
        If ($deleteAllFiles -eq "True") 
        
            $logFiles = Get-ChildItem -Path $dir -Force -Exclude $fileExclusions[0],$fileExclusions[1] | Where  $_.LastWriteTime -le "$LastWrite" 
            DeleteLogFiles($logFiles)
            #foreach($logFile in $logFiles)
            #
            #    if($logFile -ne $null)
            #    
            #        $Msg = Write-Output "$("Deleting File $logFile")" 
            #        $Msg | out-file $successLogfile -append 
            #        Remove-Item $logFile.FullName -Force
            #    
            #
         
        Else 
        
            $logFiles = Get-Childitem $dir -Include $fileTypesToDelete[0],$fileTypesToDelete[1],$fileTypesToDelete[2], $liveSiteLogs -Exclude $fileExclusions[0],$fileExclusions[1] | Where $_.LastWriteTime -le "$LastWrite"
            DeleteLogFiles($logFiles)
            #foreach($logFile in $logFiles)
            #
            #    if($logFile -ne $null)
            #    
            #        $Msg = Write-Output "$("Deleting File $logFile")" 
            #        $Msg | out-file $successLogfile -append 
            #        Remove-Item $logFile.FullName -Force
            #    
            #     
             
    

Else

    $countUnaccessibleUNCPaths++        
    #server/the UNC Path is unaccessible   
    $Msg = Write-Output  "$(Get-Date -UFormat "%D / %T") Unable to access $dir."  
    $Msg | out-file $errorLogfile -append        
  
# Call the function to Delete the AIC XML Logfiles
DeleteAICXMLLogs $dir   

#If any of the directories were unaccessible send an email to alert the team
if($countUnaccessibleUNCPaths.count -gt 0) 

# Call the function to send the email
SendEmail $emailSubject $emailFrom $emailTo


#Only keep 2 weeks worth of the FileCleaner App logs for reference purposes
If(Test-Path -Path $fileCleanerLogs)

#write to output logfile Directory info
$Msg = Write-Output "$(Get-Date -UFormat "%D / %T") - Accessing: $fileCleanerLogs"
$Msg | out-file $successLogfile

$fileCleanerLogs = Get-Childitem $fileCleanerLogs -Recurse | Where $_.LastWriteTime -le "$fileCleanerLastWrite"
DeleteLogFiles($fileCleanerLogs)
#foreach($fileCleanerLog in $fileCleanerLogs)
#
#    if($fileCleanerLog -ne $null)
#    
#        $Msg = Write-Output "$("Deleting File $fileCleanerLog")" 
#        $Msg | out-file $successLogfile -append 
#        Remove-Item $fileCleanerLog.FullName -Force
#    
#                


Function DeleteLogFiles($logFiles)

    foreach($logFile in $logFiles)
    
        if($logFile -ne $null)
        
        $Msg = Write-Output "$("Deleting File $logFile")" 
        $Msg | out-file $successLogfile -append 
        Remove-Item $logFile.FullName -Force
        
    


Function DeleteAICXMLLogs($dir)

    #Split the UNC path $dir to retrieve the server value
    $parentpath = "\\" + [string]::join("\",$dir.Split("\")[2])
    #test access to the \\server\D$\DebugXML path
    If(Test-Path -Path $parentpath$AICLogs)
    
        $Msg = Write-Output "$(Get-Date -UFormat "%D / %T") - Accessing: $parentpath$AICLogs"
        $Msg | out-file $successLogfile

        #Concantenate server value to $AICLogs to delete all xml logs in \\server\D$\DebugXML with a retention period of 30Days
        $XMLlogFiles = Get-ChildItem -Path $parentpath$AICLogs -Force -Include $fileTypesToDelete[3]-Recurse -Exclude $fileExclusions[0],$fileExclusions[1] | Where  $_.LastWriteTime -le "$AICLastWrite" 
        #get each file and add the filename to be deleted to the successLogfile before deleting the file 
        DeleteLogFiles($XMLlogFiles)
    #foreach($XMLlogFile in $XMLlogFiles)
    #
    #    if($XMLlogFile -ne $null)
    #    
    #        $Msg = Write-Output "$("Deleting File $XMLlogFile")" 
    #        $Msg | out-file $successLogfile -append 
    #        Remove-Item $XMLlogFile.FullName -Force
    #    
    #      

Else

    $Msg = Write-Output "$("$parentpath$AICLogs does not exist.")"
    $Msg | out-file $successLogfile -append   



Function SendEmail($emailSubject, $emailFrom, $emailTo)
       
    $MailMessage = New-Object System.Net.Mail.MailMessage
    $SMTPClient = New-Object System.Net.Mail.smtpClient
    $SMTPClient.host = $smtpServer
    $Recipient = New-Object System.Net.Mail.MailAddress($emailTo, "Recipient")
    $Sender = New-Object System.Net.Mail.MailAddress($emailFrom, "Sender")

    $MailMessage.Sender = $Sender
    $MailMessage.From = $Sender
    $MailMessage.Subject = $emailSubject        
    $MailMessage.Body = @"
    This email was generated because the FileCleaner script was unable to access some UNC Paths, please refer to $errorLogfile for more information. 

Please inform the Team if you plan to resolve this.

This is an automated email please do not respond.
"@
    $SMTPClient.Send($MailMessage)

调试时出现以下错误:

DeleteAICXMLLogs : 术语“DeleteAICXMLLogs”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。 检查名称的拼写,或者如果包含路径,请验证 路径正确,然后重试。在 C:\Users\pmcma\Documents\Projects\用 PowerShell 替换 FileCleaner 脚本\FileCleaner.ps1:158 字符:5 + 删除AICXMLLogs $dir + ~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (DeleteAICXMLLogs:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

SendEmail : 术语“SendEmail”未被识别为 cmdlet、函数、脚本文件或可运行的程序。检查拼写 的名称,或者如果包含路径,请验证该路径是 正确并重试。在 C:\Users\pmcma\Documents\Projects\Replace 带有 PowerShell 脚本的 FileCleaner\FileCleaner.ps1:164 char:5 + SendEmail $emailSubject $emailFrom $emailTo +~~~~~~~~~ + CategoryInfo : ObjectNotFound: (SendEmail:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

DeleteLogFiles : 术语“DeleteLogFiles”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。查看 名称的拼写,或者如果包含路径,请验证 路径正确,然后重试。在 C:\Users\pmcma\Documents\Projects\用 PowerShell 替换 FileCleaner Script\FileCleaner.ps1:175 字符:5 + DeleteLogFiles($fileCleanerLogs) + ~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (DeleteLogFiles:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

我认为声明或调用函数的方式没有任何问题。任何想法为什么这个脚本会失败?

【问题讨论】:

【参考方案1】:

PowerShell 脚本是从上到下读取的,因此在定义它们之前您不能使用任何引用,很可能这就是您收到错误的原因。 尝试在调用它们的位置上方添加函数定义块。

或者,您可以创建一个具有全局范围的函数。只需在函数名称前加上关键字 global: like,

function global:test ($x, $y)

    $x * $y 

【讨论】:

【参考方案2】:

我也遇到过这种情况。尝试将函数放在业务逻辑之前。这是一个脚本,不是编译代码。因此,在您调用它们之前,尚未声明这些函数。

【讨论】:

以上是关于Powershell脚本无法识别函数的主要内容,如果未能解决你的问题,请参考以下文章

Powershell 无法识别Path Powershell 如何更新Path

Powershell 无法识别Path Powershell 如何更新Path

markdown Powershell无法识别与NPM全局包相关的命令

Azure DevOps - 在 powershell 中无法识别“Get-AzSubscription”

YAML 管道中无法识别术语“System.DefaultWorkingDirectory”

为啥 Javascript 无法识别我的构造函数?