【问题标题】:How to ensure IIS website is completely stopped in Powershell?如何确保 IIS 网站在 Powershell 中完全停止?
【发布时间】:2016-05-09 16:24:20
【问题描述】:

我有一个 Powershell 脚本,它可以停止 IIS 网站和相应的应用程序池,然后删除应用程序日志(log4net 日志)。这是脚本sn-p:

stop-website -name "MyWebsite"
stop-webapppool -name "MyWebsite"
del c:\inetpub\MyWebsite\logs\*.*

问题是 stop-website 和 stop-webapppool 似乎在网站完全关闭之前返回,这导致删除失败,说明文件正在被另一个进程使用:

del:无法删除项目 C:\inetpub\MyWebsite\logs\App.log:该进程无法访问文件“C:\inetpub\MyWebsite\logs\App.log”,因为它正被另一个进程使用。

如果我在停止命令和 del 命令之间添加 10 秒睡眠,则日志将成功删除。虽然这是非常骇人听闻的,但并不可靠。有没有办法强制 stop-website/stop-webapppool 命令在网站/应用程序池完全停止之前不返回?

谢谢。


从以下链接实施的解决方案。如果 IIS 进程没有停止,我将等待大约 60 秒,然后终止它。

https://greenfinch.ie/blog/powershellscript.html

        "Stopping IIS site [$name]" >> $logFile
        stop-website -name $name

        "Stopping app pool [$name]" >> $logFile
        stop-webapppool -name $name

        $sleepTime = 5
        $processId = $TRUE
        while ($processId)
        {
            $processId = Get-WmiObject -Class win32_process -filter "name='w3wp.exe'" |
                            ?{ ($_.CommandLine).Split("`"")[1] -eq $name } |
                            %{ $_.ProcessId }

            if ($sleepTime -gt 60)
            {
                "Waited [$sleepTime] sec for process [$processId] to stop and it is still running. Killing it." >> $logFile
                Stop-Process $processId
                break
            }

            if ($processId)
            {
                "App pool [$name] is running with process ID: [$processId]. Sleeping for [$sleepTime] sec and then checking again." >> $logFile
                Start-Sleep -s $sleepTime
                $sleepTime = $sleepTime + 10
            }
        }

【问题讨论】:

    标签: powershell iis


    【解决方案1】:

    您可以使用这两个命令来检查网站/应用程序的状态,例如10秒后,然后仅在返回的状态为stopped时使用If语句删除日志

    Get-WebsiteState -name "MyWebsite"
    Get-WebAppPoolState -name "MyWebsite"
    

    这个循环也应该对你有所帮助

    $currentRetry = 0;
    $success = $false;
    do{
        $status = Get-WebAppPoolState -name "MyWebsite"
        if ($status -eq "Stopped"){
             <....your code here....>
                $success = $true;
            }
            Start-Sleep -s 10
            $currentRetry = $currentRetry + 1;
        }
    while (!$success -and $currentRetry -le 4)
    

    2019 年 4 月 24 日更新

    根据评论和当前cmdlet document,看来返回类型确实是一个对象。因此,大概可以按照注释或下面的线 sn-p 处理。作者无法再访问 Windows Server 环境,因此没有直接修改原始答案,也无法测试更新

    if ($status.Value -eq "Stopped")
    

    【讨论】:

    • 我做了一个调整以将应用程序池状态作为字符串获取:$status = (Get-WebAppPoolState -name "MyWebsite").Value
    • 这不起作用。 $status 是一个对象。您必须按照前面的评论中所述获取该对象的值。
    【解决方案2】:

    运行“Stop-WebAppPool”后,WebAppPool 的状态将变为“Stopping”,可能需要几秒钟后 WebAppPool 的状态才会真正变为“Stopped”。
    这是一个帮助 WebAppPoolState 的小函数

    function Stop-AppPool ($webAppPoolName,[int]$secs) {
    $retvalue = $false
    $wsec = (get-date).AddSeconds($secs)
    Stop-WebAppPool -Name $webAppPoolName
    Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
    $poolNotStopped = $true
    while (((get-date) -lt $wsec) -and $poolNotStopped) {
        $pstate =  Get-WebAppPoolState -Name $webAppPoolName
        if ($pstate.Value -eq "Stopped") {
            Write-Output "$(Get-Date): WebAppPool '$webAppPoolName' is stopped"
            $poolNotStopped = $false
            $retvalue = $true
        }
    }
    return $retvalue
    }
    

    您可以使用例如运行此功能

    Stop-AppPool "MyWebsite" 30
    

    并检查返回值以查看 WebAppPool 是否在给定的秒数内停止

    【讨论】:

      【解决方案3】:

      停止应用程序池并使其进入已停止状态的最简单方法是使用appcmd.exe。当应用程序池真正停止时它会返回,否则你会得到一个错误

      只需在 PowerShell 上执行此操作:

      & $env:windir\system32\inetsrv\appcmd.exe stop apppool /apppool.name:"YourAppPoolName"
      

      当您的 AppPool 正确弯腰时,您将收到以下消息:

      “YourAppPoolName”成功停止

      【讨论】:

        【解决方案4】:

        这是我使用 Get-IISServerManager 的方法。

        $manager = Get-IISServerManager      
        $site = $manager.Sites["mySiteName"]
        
        if($site.State -ne "Stopped") {
          $site.Stop()
        }
        
        while ($site.State -ne "Stopped") {
          "waiting 1 second for site to stop..."
          Start-Sleep -s 1
        }
        
        "site stopped"
        

        【讨论】:

          【解决方案5】:

          我修复了@user4531 代码如果应用程序池在此之前停止,则会失败:

          function Stop-AppPool ($webAppPoolName,[int]$secs) {
              $retvalue = $false
              $wsec = (get-date).AddSeconds($secs)
          
              $pstate =  Get-WebAppPoolState -Name $webAppPoolName
          
              if($pstate.Value -eq "Stopped") {
                   Write-Output "WebAppPool '$webAppPoolName' is stopped already"
                   return $true
              }
          
              Stop-WebAppPool -Name $webAppPoolName
              Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
              $poolNotStopped = $true
              while (((get-date) -lt $wsec) -and $poolNotStopped) {
                  $pstate =  Get-WebAppPoolState -Name $webAppPoolName
                  if ($pstate.Value -eq "Stopped") {
                      Write-Output "WebAppPool '$webAppPoolName' is stopped"
                      $poolNotStopped = $false
                      $retvalue = $true
                  }
              }
              return $retvalue
          }
          

          可以这样使用:

          Stop-AppPool "SSO" 30
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多