Unable to export the IIS result to CSV - powershell

I have created a script to get all the IIS Sites and App-pool details from multiple servers, the script is working fine as expected, but I am unable to export the results to CSV file.
It will helpful if someone suggest on how can I export the output details to CSV file.
CODE
#Import-Module -Name WebAdministration
$Computers = Get-Content "C:\Desktop\Scripts\Servers.txt"
foreach ($server in $Computers) {
$iis = Get-WmiObject Win32_Service -Filter "Name = 'IISADMIN'" -ComputerName $server
if ($iis.State -eq 'Running')
{
$details = Write-Host "IIS is running on $server" -ForegroundColor Green
#Chandu
Invoke-Command -ComputerName $Computers -ScriptBlock {
# Changed to newer IISAdministration Module to match Get-IISAppPool
$Websites = Get-IISSite
foreach ($Website in $Websites) {
$AppPool = Get-IISAppPool -Name $Website.Applications[0].ApplicationPoolName
#$Website.ApplicationPool
[PSCustomObject]#{
Server_Name = $env:COMPUTERNAME +'.'+ $env:USERDNSDOMAIN
Website_Name = $Website.Name
Website_Id = $Website.Id -join ';'
Website_State = $Website.State -join ';'
Website_PhysicalPath = $Website.PhysicalPath -join ';'
Website_Bindings = $Website.Bindings.Collection -join ';'
Website_Attributes = ($Website.Attributes | ForEach-Object { $_.name + "=" + $_.value }) -join ';'
AppPool_Name = $AppPool.Name -join';'
AppPool_State = $AppPool.State -join ';'
AppPool_ManagedRuntimeVersion = $AppPool.ManagedRuntimeVersion -join ';'
AppPool_ManagedPipelineMode = $AppPool.ManagedPipelineMode -join ';'
AppPool_StartMode = $AppPool.StartMode -join ';'
}
} Export-csv -Path "C:\Desktop\Scripts\IISite_App-pool_Details.csv" -Append
}
}
}
#Export-Excel -Append -Path C:\Desktop\Scripts\IISite_App-pool_Details.xlsx -AutoSize -BoldTopRow

You could add switch -HideComputerName to the Invoke-Command cal, but then still the output will also have properties 'RunspaceId' and 'PSShowComputerName' added to it.
If you don't want those, you can de-select them from the result like
$iis = Get-WmiObject Win32_Service -Filter "Name = 'IISADMIN'" -ComputerName $server
if ($iis.State -eq 'Running') {
$details = Write-Host "IIS is running on $server" -ForegroundColor Green
#Chandu
$result = Invoke-Command -ComputerName $Computers -ScriptBlock {
# Changed to newer IISAdministration Module to match Get-IISAppPool
$Websites = Get-IISSite
foreach ($Website in $Websites) {
$AppPool = Get-IISAppPool -Name $Website.Applications[0].ApplicationPoolName
#$Website.ApplicationPool
[PSCustomObject]#{
Server_Name = $env:COMPUTERNAME +'.'+ $env:USERDNSDOMAIN
Website_Name = $Website.Name
Website_Id = $Website.Id -join ';'
Website_State = $Website.State -join ';'
Website_PhysicalPath = $Website.Applications["/"].VirtualDirectories["/"].PhysicalPath -join ';'
Website_Bindings = (Get-Website -Name $Website.Name).bindings.Collection join ';'
Website_Attributes = ($Website.Attributes | ForEach-Object { $_.name + "=" + $_.value }) -join ';'
AppPool_Name = $AppPool.Name -join';'
AppPool_State = $AppPool.State -join ';'
AppPool_ManagedRuntimeVersion = $AppPool.ManagedRuntimeVersion -join ';'
AppPool_ManagedPipelineMode = $AppPool.ManagedPipelineMode -join ';'
AppPool_StartMode = $AppPool.StartMode -join ';'
}
}
}
# remove the extra properties Invoke-Command added
$result = $result | Select-Object * -ExcludeProperty 'PSComputerName','RunspaceId','PSShowComputerName'
# save the result as CSV file
$result | Export-Csv -Path "C:\Desktop\Scripts\IISite_App-pool_Details.csv" -NoTypeInformation
}
P.S. Your code doesn't show where you initialized variable $Computers..

Related

Unable to add the Ping Response to Output variable

I have written a script to export specific registry keys and the sub keys inside it with the server ping response, but my scripts works as expected but the ping response value when I add it to output it is giving null
Please help me to get the ping response value for each server.
## Clear the host
Clear-Host
## Install Export-Excel Module if it is not installed
If (-Not (Get-InstalledModule -Name ImportExcel)){
Install-Module -Name ImportExcel -ErrorAction SilentlyContinue -Force
}
## Set Script Location
Set-Location $PSScriptRoot
## Out File Name
$FileName = "$PSScriptRoot\TCPIP_Interface_Details.xlsx"
## Get full list of servers
$Servers = GC -Path ".\Servers.txt"
## Delete if Old file exists
if (Test-Path $FileName) { Remove-Item $FileName
write-host "$FileName has been deleted" -BackgroundColor DarkMagenta }
else { Write-host "$FileName doesn't exist" -BackgroundColor Red }
## Loop through each server
$Result = foreach ($vm in $Servers) {
## Check the Ping reponse for each server
Write-Host "Pinging Server" $vm
$Ping = Test-Connection -Server $vm -Quiet -Verbose
if ($Ping){Write-host "Server" $vm "is Online" -BackgroundColor Green}
else{Write-host "Unable to ping Server" $vm -BackgroundColor Red}
## Check the Network Share path Accessibility
Write-Host "Checking Share Path on" $vm
$SharePath = Test-Path "\\$vm\E$" -Verbose
if ($SharePath){Write-host "Server" $vm "Share Path is Accessible" -BackgroundColor Green}
else{Write-host "Server" $vm "Share path access failed" -BackgroundColor Red}
Invoke-Command -ComputerName $vm {
## Get ChildItems under HKLM TCPIP Parameter Interface
Get-ChildItem -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces' | ForEach-Object {
Get-ItemProperty -Path $_.PSPath | Where-Object { $_.PsObject.Properties.Name -like 'Dhcp*' }
} | Select-Object -Property #{Name = 'ComputerName'; Expression = {$env:COMPUTERNAME+"."+$env:USERDNSDOMAIN}},
#{Name = 'Ping_Response'; Expression = {if($using:Ping) {'Pinging'} else {'Unable to ping'}}},
#{Name = 'Share_Path_Access'; Expression = {if($using:SharePath) {'Accessible'} else {'Not Accessible'}}},
DhcpIPAddress, #{Name = 'DhcpNameServer'; Expression = {$_.DhcpNameServer -split ' ' -join '; '}},
DhcpServer, #{Name = 'DhcpDefaultGateway'; Expression = {$_.DhcpDefaultGateway -join '; '}}
}}
$Result | Select-Object * -Exclude PS*, RunspaceId
As commented, just change your calculated property into
#{Name = 'Ping_Response'; Expression = {$using:Ping}}
By scoping the variable $Ping with using:, it will be known in the scriptblock for Invoke-Command. Without that, the scritblock simply sees it as new, undefined variable (i.e. $null)
If as you commented, you would rather see some text instead of just True or False, have the expression in that calculated property output whatever you want like:
#{Name = 'Ping_Response'; Expression = {if($using:Ping) {'Pinging'} else {'Unable to ping'}}}
Another way of letting the scriptblock know what $Ping is, is by adding this to the command as parameter:
Invoke-Command -ComputerName $vm {
param([bool]$Ping)
# ... the rest of the scriptblock
# now, you do not have to use the `using:` scope on $Ping
} -ArgumentList $Ping
To answer your latest comment, if pinging the machine did not work, there is really no reason to try and get properties from it using Invoke-Command. If you also want to have the non-pingables in your output, do:
$result = foreach ($vm in $Servers) {
$Ping = Test-Connection -Server $vm -Quiet -Verbose
if ($Ping) {
# we can reach this machine, so gather the properties we need and output an object
# the 'Ping_Response 'can now be hardcoded
Invoke-Command -ComputerName $vm -ScriptBlock {
Get-ChildItem -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces' | ForEach-Object {
Get-ItemProperty -Path $_.PSPath | Where-Object { $_.PsObject.Properties.Name -like 'Dhcp*' }
}
} |
Select-Object -Property #{Name = 'ComputerName'; Expression = {$_.PSComputerName}},
#{Name = 'Ping_Response'; Expression = { 'Pinging' }},
DhcpIPAddress,
#{Name = 'DhcpNameServer'; Expression = {$_.DhcpNameServer -split ' ' -join '; '}},
DhcpServer,
#{Name = 'DhcpDefaultGateway'; Expression = {$_.DhcpDefaultGateway -join '; '}}
}
else {
# return a similar object for machines that didn't respond to Ping
# since we cannot reach this machine, most properties will be empty
'' | Select-Object -Property #{Name = 'ComputerName'; Expression = {$vm}},
#{Name = 'Ping_Response'; Expression = { 'Unable to ping' }},
DhcpIPAddress,DhcpNameServer,DhcpServer,DhcpDefaultGateway
}
}
# output the results
$result | Select-Object * -ExcludeProperty PS*, RunspaceId | Export-Csv -Path "C:\temp\TCPIP_Interface_Details.csv" -NoTypeInformation

Powershell IIS Audit Scripting

I'm in the early stages of learning powershell, and I'm trying to put together a script that remotely gathers information from our IIS servers, but I'm encountering several issues.
The first one is that the IP Address and OU columns remain empty in the output file.
The second one is that I'm not able to format the Administrator group column to have 1 group per line, or delimited by commas.
This is the current version of the code:
$computers = Get-Content "C:\servers.txt"
#Running the invoke-command on remote machine to run the iisreset
$output = foreach ($computer in $computers)
{
Write-Host "Details from server $computer..."
try{
Invoke-command -ComputerName $computer -ErrorAction Stop -ScriptBlock{
# Ensure to import the WebAdministration and AD module
Import-Module WebAdministration
Import-Module ActiveDirectory
$webapps = Get-WebApplication
$list = #()
foreach ($webapp in get-childitem IIS:\AppPools\)
{
$name = "IIS:\AppPools\" + $webapp.name
$item = #{}
$item.server = $env:computername
$item.WebAppName = $webapp.name
$item.Version = (Get-ItemProperty $name managedRuntimeVersion).Value
$item.State = (Get-WebAppPoolState -Name $webapp.name).Value
$item.UserIdentityType = $webapp.processModel.identityType
$item.Username = $webapp.processModel.userName
$item.Password = $webapp.processModel.password
$item.OU = (Get-ADComputer $_ | select DistinguishedNAme)
$item.IPAddress = (Get-NetIPAddress -AddressFamily IPv4)
$item.Administrators = (Get-LocalGroupMember -Group "Administrators")
$obj = New-Object PSObject -Property $item
$list += $obj
}
$list | select -Property "Server","WebAppName", "Version", "State", "UserIdentityType", "Username", "Password", "OU", "Ip Address", "Administrators"
}
} catch {
Add-Content .\failedservers.txt -Force -Value $computer
}
}
$output | Export-Csv -Path .\output.csv
#Stop-Transcript
I'd really appreciate any input on how to get it to work properly or improve on the code itself.
Thanks in advance!
For the OU property, you'll want to reference $env:COMPUTERNAME instead of $_:
$item.OU = (Get-ADComputer $env:COMPUTERNAME |Select -Expand DistinguishedName)
For the IPAddress and Administrators fields you'll want to use -join to create comma-separated lists of the relevant values:
$item.IPAddress = (Get-NetIPAddress -AddressFamily IPv4).IPAddress -join ','
$item.Administrators = (Get-LocalGroupMember -Group "Administrators").Name -join ','

Test-connection for remote pcs

I have the following powershell with the aim of collecting a reg value from a list of remote machines, Ive tried using a test-connection to speed up process where devices are not online but the test-connection fails for all....
Here is the script:
clear
$servers = Get-Content -Path C:\ukdeviceswin10.txt
$PatternSID = 'S-1-5-21-\d+-\d+\-\d+\-\d+$'
$ProfileList = ForEach ($server in $servers)
{ if(test-connection $server -quiet -count 1)
{
invoke-command -computername $server {gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | Where-Object {$_.PSChildName -match $PatternSID} |
Select #{name="SID";expression={$_.PSChildName}}}}
foreach ($profile in $profilelist) {
$profile = $profile -replace ".$"
$profile = $profile.substring(6,46)
$profile = $profile -replace "[;]"
$profile = $profile -replace "[ ]"
$profiletest = $profile.substring(0,8)
if ($profiletest -eq "S-1-5-21"){
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::Users, "$server")
$profilekey = $profile + "\\SOFTWARE\\Microsoft\\Office\\Outlook\\Addins\\CofenseOutlookReporter.AddinModule"
$RegKey= $Reg.OpenSubKey("$profilekey")
if ($regKey -eq $null){} else {$LoadbehaviourVersion = $RegKey.GetValue("LoadBehaviour")
$results = $server + " " + $profile + " " + $LoadbehaviourVersion | out-file -filepath c:\dell\regresults.txt -Append
}
$RegKey=""
$LoadbehaviourVersion=""
}
}
}

PowerShell - List all computers & which users are administrators

I am trying to create a powershell script that:
Finds all computers in the domain
Queries each computer to determine what groups/users are in the Administrators group
Lists each user/group/computer
The columns should be: Username, GroupName, ComputerName, DomainName
Here's where I am at so far, but I'm looking for some help parsing the WMI results in a consistent fashion, or per
Here's the script so far:
$auditdir = "c:\temp\"
$tempfile = $auditdir + "computers.csv"
$computers = (Get-ADComputer -Filter *)
$Table = #()
$Record = #{
"MachineName" = ""
"GroupName" = ""
"DomainName" = ""
"Username" = ""
}
Foreach ($computername in $computers){
$computername = $computername.name
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS){
Write-Host "Output current admin"
$admin
Write-Host "Clean up current admin"
$admin = ($admin | Out-String)
$admin = $admin -replace 'cimv2', '' -replace 'Win32','' -replace 'useraccount','' -replace 'root','' -replace $computername,'' -replace ',','' -replace "`n|`r" -replace $env:userdomain,'' -replace 'name','' -replace '=','' -replace ':','' -replace '_','' -replace '\\','' -replace '_','' -replace 'group','' -replace '""',''
$admin.substring(8)
$admin
$admin = $admin | %{$_.split('"')[3]}
$admin
Write-Host "done with current admin"
$Record."Machinename" = $computername
$Record."Groupname" = $admin
$Record."DomainName" = $env:USERDNSDOMAIN
$Record."UserName" = $admin.split("")[1]
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
$Table | Export-Csv $tempfile -NoTypeInformation
}
Can someone please help me get to the finish line?
Update 1:
With Mathias's help, I've cast the results of the WMI query to a WMI type and can access items easier.
$auditdir = "c:\temp\"
$tempfile = $auditdir + "computers.csv"
$computers = (Get-ADComputer -Filter *)
$Table = #()
$Record = #{
"ComputerName" = ""
"MemberName" = ""
"DomainName" = ""
"SID" = ""
}
Foreach ($computername in $computers){
$computername = $computername.name
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS){
$admin = [WMI]$admin
$admin
$Record."ComputerName" = $computername
$Record."MemberName" = $admin.name
$Record."DomainName" = $env:USERDNSDOMAIN
$Record."SID" = $admin.SID
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
$Table | Export-Csv $tempfile -NoTypeInformation
}
I seem to be running into an issue with domain admins group. It can't seem to be converted to WMI and then parsed.
Error is:
Cannot convert value "\\computername\root\cimv2:Win32_Group.Domain="domain",Name="Domain Admins"" to type
"System.Management.ManagementObject". Error: "Not found "
At C:\Users\f12admin\Desktop\computerlist.ps1:20 char:3
+ $admin = [WMI]$admin
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastToWMI

Using powershell to modify notes.ini

I have a powershell script that parses a lotus notes INI file and replaces text inside the file. But only the replaced text is showing up in the output file.
# Example of PowerShell -replace parameter
## Get-DistinguishedName -- look up a DN from a user's (login) name
function Get-DistinguishedName {
Param($UserName)
$ads = New-Object System.DirectoryServices.DirectorySearcher([ADSI]'')
$ads.filter = "(&(objectClass=Person)(samAccountName=$UserName))"
$s = $ads.FindOne()
return $s.GetDirectoryEntry().DistinguishedName
}
clear-Host
set-executionpolicy remotesigned
$original_file = '.\notes.ini'
$destination_file = '.\notes2.ini'
$OS = Get-WmiObject -Class win32_OperatingSystem -namespace "root\CIMV2" -ComputerName .
$username = [Environment]::UserName
$userprofile = $env:userprofile
$fullname = Get-DistinguishedName($username) | %{$data = $_.split(","); $data[0].Substring(3)}
write-Host "Creating $userprofile"
if (($OS.Version -eq "5.1.2600") -or ($OS.Version -eq "5.2.3790")) {
$lookupTable = #{
'^SU_FILE_CLEANUP=' = 'SU_FILE_CLEANUP=' + $userprofile + '\Local Settongs\Application Data\smkits'
'%username%' = $username
'%fullname%' = $fullname
'%userprofile%' = $userprofile
'^Directory=' = 'Directory=' + $userprofile + '\Local Settongs\Application Data\Lotus\Notes\Data'}
} else {
$lookupTable = #{
'SU_FILE_CLEANUP=' = 'SU_FILE_CLEANUP=' + $userprofile + '\AppData\Roaming\smkits'
'%username%' = $username
'%fullname%' = $fullname
'%userprofile%' = $userprofile
'Directory=' = 'Directory=' + $userprofile + '\AppData\Local\Lotus\Notes\Data'}
}
Get-Content -Path $original_file | ForEach-Object {
$line = $_
$lookupTable.GetEnumerator() | ForEach-Object {
if ($line -match $_.Key)
{
$line -replace $_.Key, $_.Value
#break
}
}
write-Host $line
} | Set-Content -Path $destination_file
What am I missing
On this line, you are writing he output of the replace operator onto the pipeline, this will then get picked up by Set-Content
$line -replace $_.Key, $_.Value
whereas on this line, you are writing the output to the host (i.e. the powershell console) it will not end up on the pipeline and will not get picked up up Set-Content:
write-Host $line
To fix this, just replace write-host with write-output:
Write-Output $line