Application Owners Self Service Solution

Infraself For The Application Owners

Hi ,

This time, I would like to tell you a small story about my application owners demands, request and a self service solution.

In my corporate company internal web site application owners stores their applications on-prem servers which I am in responsible infrastructure systems. Test, Development and Prod systems infrastructure are different but all of them on-prem. When the developers made some changes on the application configurations sometimes they can have a new code or updates about the application. They always came to me for the application service restart, application pool restart or even server restarts.

This is a annoying process for me and also for them. They are the responsible application but I have to take care of the application running status. Sometimes they can upload the wrong code or bugy codes. They need to update their codes and redeploy it to infrastructure (10) ten times in a day. That means I have to restart the services eleven (11) times in a day. No it was not  suitable  for  my working style !

In corporate rules application owners can’t have admin rights on any systems. So I need to find a solution for them and for my self.

I spoke to my manager about this process, he told me OK if you could find a suitable solution about it , he will gave me full support but with this conditions which are;

  1. With this solution they shouldn’t have  admin rights on any server,
  2. They shouldn’t have to have make a remote connection to any server,
  3. They could able to restart their own applications services or servers,
  4. On that systems every actions which they made ( restart , stop, start etc..) should be logged,
  5. They should not have get any admin rights user accounts information on that systems from any script or application.

So it seems a challenge, and yes Challenge Accepted !

What I got in my hands ;

  • All application working systems are Windows Servers versions,
  • All application owners willing to take care of the application full life cycle,
  •  Power shell scripts will be fine for all run windows operations.
  • Our MS licensing are giving me a freedom for all MS Products.

 How I solved my and application owners problem;

I have build a RDWeb Cluster systems for it. Two servers are accepting the connections with cluster build and they forwarding the RDP sessions to backend application sharing servers.  So with this operation users don’t know the RDP Servers. I have shared the Poweshell scripts via  RDWeb.

When users logon to RDWeb , if any powershell script shared with the user. Users can see the script. When click on the script , script is start to run on backend application server, so users can not see the script meta. I have sold the rest of the problems in side of the Powershell whic it was the easy part.

Here is the service restart script;

# Service Restart Script.
CLS
Function pause ($message)
{
# Check if running Powershell ISE
if ($psISE)
{
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("$message")
}
else
{
Write-Host "$message" -ForegroundColor Darkgreen
$x = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}

$Currentuser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$Username = 'Admin or service User Info'
$Password = 'Admin or service User Password'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$SecureString = $pass
# Users you password securly
$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$SecureString 
filter timestamp {"$(Get-Date -Format G): $_"}
$owner = 'App server_Service_Restart Script'
$ServerName = 'Application Server Hostname'
$LogPath = '\Shared\Log Path\to every\application sharing \_Restart.log'
$To = "application owner email"
$From = "from email"
$Subject = "Service Status Info"
$Cc = "monitoring team email grup"
$SmtpServer = "SMTP Server hostname"
$JobTime = Get-Date

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Select the Service !!!'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Select Your Service:'
$form.Controls.Add($label)

$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 80

[void] $listBox.Items.Add('Service Name 1')
[void] $listBox.Items.Add('Service Name 2')
[void] $listBox.Items.Add('Service Name 2')
[void] $listBox.Items.Add('Service Name 2')
[void] $listBox.Items.Add('Service Name 2')

$form.Controls.Add($listBox)

$form.Topmost = $true

$result = $form.ShowDialog()

While ($true) {

if ($result -eq [System.Windows.Forms.DialogResult]::OK)

{
$x = $listBox.SelectedItem

$ITMessage = "If you have a trouble on $x please contact with ITI."


Write-Host Which operation would you like to run on Service $x ?
Write-Host ----------------------------
Write-Host 1 - Start 
Write-Host 2 - Stop
Write-Host 3 - Restart
Write-Host 4 - Check Service Status
Write-Host 5 - Kill the Service Process Manually
Write-Host 0 - Exit
Write-Host ----------------------------
Write-Host Please enter only number of the command . 
}

$command = Read-Host -Prompt 'Please enter the command number '

If ($command -eq 1) {

$sonuc = Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (Start-Service -InputObject $x -PassThru | select Status,Name,PSComputerName) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x Service is started by $Currentuser via $owner at $JobTime on $ServerName " -SmtpServer $SmtpServer
Write-Output "$x Service is started by $Currentuser via $owner $ServerName"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 2) {

$sonuc = Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (Stop-service -inputObject $x -PassThru | select Status,Name,PSComputerName) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x Service is stoped by $Currentuser via $owner at $JobTime on $ServerName " -SmtpServer $SmtpServer
Write-Output "$x Service is stoped by $Currentuser via $owner on $ServerName"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 3) {

$sonuc = Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (Restart-Service -inputObject $x -PassThru | select Status,Name,PSComputerName) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x Service is restarted by $Currentuser via $owner at $JobTime on $ServerName" -SmtpServer $SmtpServer
Write-Output "$x Service is restarted by $Currentuser via $owner on $ServerName"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 4) {

$sonuc = Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (Get-Service -inputObject $x | select -Property Status,Name,PSComputerName)} -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x Service is checked by $Currentuser via $owner at $JobTime on $ServerName" -SmtpServer $SmtpServer
Write-Output "$x Service is checked by $Currentuser via $owner on $ServerName"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 5) {

$id = Get-WmiObject -computername $Servername -credential $MySecureCreds -Class Win32_Service -Filter "Name LIKE '$x'" | Select-Object -ExpandProperty ProcessId
$procname = Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($id) Get-Process -id $id |Select-Object -ExpandProperty Processname} -ArgumentList $id 
Write-Host $x Service Process Name is $procname and the process is killing now.
Invoke-command -credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($procname)get-process $procname | Stop-Process -Force -PassThru} -ArgumentList $procname
Write-Host $procname is killed and $x service is need to start again. -ForegroundColor Green 
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x Service process is killed by $Currentuser via $owner at $JobTime on $ServerName " -SmtpServer $SmtpServer
Write-Output "$x Service process is killed by $Currentuser via $owner on $ServerName"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 0) {
CLS
Exit
}

Else {
Write-Host "Please enter only number of the command !!! " -ForegroundColor Red
}
}
#App pool Restart Script
CLS
Function pause ($message)
{
# Check if running Powershell ISE
if ($psISE)
{
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("$message")
}
else
{
Write-Host "$message" -ForegroundColor Darkgreen
$x = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
}

$Currentuser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$Username = 'Admin or Service Account'
$Password = 'Password of Admin or Service Account'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$SecureString = $pass
# Users you password securly
$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username,$SecureString 
filter timestamp {"$(Get-Date -Format G): $_"}
$owner = 'Log Name '
$ServerName = 'IIS Server Hostname'
$LogPath = 'Log full path \share\logs\apppool_restart.log'
$To = "apppool owner email"
$From = "ServiceRestart@domain.com"
$Subject = "Service Status Info"
$Cc = "monitoring team email"
$SmtpServer = "smtp server hostname or fqdn"
$JobTime = Get-Date

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Please select App !!!'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'IIS AppPool Select:'
$form.Controls.Add($label)

$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 80

[void] $listBox.Items.Add('Web App Pool 1')
[void] $listBox.Items.Add('Web App Pool 2')
[void] $listBox.Items.Add('Web App Pool 3')
[void] $listBox.Items.Add('Web App Pool 4')
[void] $listBox.Items.Add('Web App Pool 5')
[void] $listBox.Items.Add('Web App Pool 6')


$form.Controls.Add($listBox)

$form.Topmost = $true

$result = $form.ShowDialog()

While ($true) {

if ($result -eq [System.Windows.Forms.DialogResult]::OK)

{
$x = $listBox.SelectedItem 

$ITMessage = "If you have a trouble on $x please contact with ITI."

Write-Host Which operation would you like to run on AppPool $x ?
Write-Host ----------------------------
Write-Host 1 - Start 
Write-Host 2 - Stop
Write-Host 3 - Restart
Write-Host 4 - Check Apppool status
Write-Host 0 - Exit
Write-Host ----------------------------
Write-Host Please enter only number of the command . 
}

$command = Read-Host -Prompt 'Please enter the command number '

If ($command -eq 1) {

$sonuc = Invoke-command –credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (C:\Windows\System32\inetsrv\appcmd.exe start apppool "$x" ) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
end-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x App Pool is started by $Currentuser via $owner at $JobTime " -SmtpServer $SmtpServer
Write-Output "$x App Pool is started by $Currentuser via $owner"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 2) {

$sonuc = Invoke-command –credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (C:\Windows\System32\inetsrv\appcmd.exe stop apppool "$x" ) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x App Pool is stoped by $Currentuser via $owner at $JobTime " -SmtpServer $SmtpServer
Write-Output "$x App Pool is stoped by $Currentuser via $owner"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 3) {

$sonuc = Invoke-command –credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (C:\Windows\System32\inetsrv\appcmd.exe recycle apppool "$x" ) } -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x App Pool is restarted by $Currentuser via $owner at $JobTime " -SmtpServer $SmtpServer
Write-Output "$x App Pool is restarted by $Currentuser via $owner"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 4) {

$sonuc = Invoke-command –credential $MySecureCreds -ComputerName $ServerName -ScriptBlock {param ($x) (C:\Windows\System32\inetsrv\appcmd.exe list apppool "$x" /text:state )} -ArgumentList $x
Write-Host $sonuc -ForegroundColor Green
Send-MailMessage -To $to -From $from -Cc $Cc -Subject $subject -Body "$x App Pool is checked by $Currentuser via $owner at $JobTime " -SmtpServer $SmtpServer
Write-Output "$x App Pool is checked by $Currentuser via $owner"| timestamp >> $LogPath
Write-Host $ITMessage
pause "Press any key to continue"
CLS
}

ElseIf ($command -eq 0) {
CLS
Exit
}

Else {
Write-Host "Please enter only number of the command !!! " -ForegroundColor Red
}
}

If you are familiar with powershell, I belive , I don’t need to explain the scripts steps.

With this powershell script they can able restart their own applications system services or web app pools . It is easy and simple solution for all of us.

In other hand that means less admin effort for me 🙂

Let me show you an example ;