PowerShell Script to Disable/Re-enable a TCP/IP Port - powershell

Is there a way to disable and re-enable a known TCP/IP port in PowerShell?

I'll make the blind assumption that you are talking about disabling & enabling TCP/IP sockets that are hosted by IIS. (Not, say, looking for ways to block/unblock things at the Firewall level, or something else entirely.) In that case, I happen to have the necessary scripts lying around...
# Get the IIsWebServer and IIsWebServerSetting WMI objects matching a display name, and combine them into one object
function Get-IIsWeb
{
param (
[string] $displayName = "",
[string] $computer = "localhost"
)
if ($displayName -eq "")
{ $filter = "" }
else
{ $filter = "ServerComment='$displayName'"}
Get-WmiObject -namespace "root\MicrosoftIISv2" -class "IIsWebServerSetting" -filter $filter -computer $computer -authentication 6 | % {
$temp = $_
Get-WmiObject -namespace "root\MicrosoftIISv2" -class "IIsWebServer" -filter "Name='$($_.Name)'" -computer $computer -authentication 6 |
add-member -membertype NoteProperty -name Settings -value $temp -passthru
}
}
# Stop all websites on a given computer that are bound to the specified port, unless they are scoped to a
# host header or IP address
function Stop-WebsiteOnPort
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, valuefrompipeline=$true)]
[int] $port,
[Parameter(Position=0)]
[string] $computer = "localhost",
[Parameter()]
[string] $hostName = $null,
[Parameter()]
[string] $ip = $null
)
begin { $websites = Get-IIsWeb -computer $computer }
process
{
# I don't think you can do this filter in WQL
$websites |
? {
( $_.settings.serverbindings | ? {$_.port -eq $port -and $_.Hostname -eq $hostName -and $_.IP -eq $ip} | measure).count -gt 0
} |
% {
$_.stop()
}
}
}
The actual WMI code to re-enable a site is pretty much identical to the code for stopping one seen above. However, you'll need to do a little more work: there could be arbitrarily many sites configured to use a given port, but only 1 can run at a time. Either you'll need an additional parameter from the user, or some heuristic for picking the "right" site.

Related

PowerShell to find computers in the domain, user is logged on

I am fairly new to PowerShell. I have this script working for computer names on the domain, thanks to #Adam Bertram https://4sysops.com/archives/how-to-find-a-logged-in-user-remotely-using-powershell/.
I understand it and it works fine on my domain i.e. I can query the computer name and it returns a list of logged users. I have difficulties altering the code so it could return a list of computer names for a given user, instead. I believe the issue could be with the correct Win32 class.
function Get-LoggedOnUser
{
[CmdletBinding()]
param
(
[Parameter()]
[ValidateScript({ Test-Connection -ComputerName $_ -Quiet -Count 1 })]
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)
foreach ($comp in $ComputerName)
{
$output = #{ 'ComputerName' = $comp }
$output.UserName = (Get-WmiObject -Class win32_computersystem -ComputerName $comp).UserName
[PSCustomObject]$output
}
}
thanks
Tomasz
Try this:
function Get-LoggedOnUser
{
[CmdletBinding()]
param
(
[ Parameter() ]
$UserName
)
Get-WmiObject -Class win32_computersystem | Where-Object { $_.Username -like "*$UserName*" } | Select-Object Name
}
Get-LoggedOnUser -UserName "vish"

How do you make a function that only takes strings, take variables in Powershell?

I want to run a function in Powershell called Get-OSArchitecture which tells me whether a computer has a 32bit or 64bit system when you give it a domain name. However, it only accepts strings such as "SALES-DENNY" and not variables with stored strings such as $string1. I've played around with something called Out-String but this function is really stubborn with getting strings and nothing to do with variables.
The following code is for getting the global Get-OSArchitecture function:
function global:Get-OSArchitecture {
#Requires -Version 2.0
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$false,
Position=1,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[String[]]$ComputerName = $env:COMPUTERNAME
)#End Param
Begin
{
Write-Verbose "Retrieving Computer Info . . ."
}
Process
{
$ComputerName | foreach {
$ErrorActionPreference = 0
$Computer = $_
$Windir,$OSArchitecture,$OSVersion = Get-WmiObject -class Win32_OperatingSystem -ComputerName $_ |
foreach {$_.WindowsDirectory,$_.OSArchitecture,$_.Version}
$SysDrive = ($Windir -split ":")[0] + "$"
# $OSVersion[0]
# $OSArchitecture is only suppored on OSVersion -ge 6
# I was going to test for that, however now I just test if $OSArchitecture -eq $True
Write-Verbose "Operating System version on $Computer is: $OSVersion"
if ($OSArchitecture)
{
New-Object PSObject -Property #{
Hostname=$Computer
OSArchitecture=$OSArchitecture
SysDrive=$SysDrive
OSVersion=$OSVersion
WinDir=$WinDir
}
}
else
{
# check the program files directory
write-verbose "System Drive on $Computer is: $SysDrive"
$x64 = "\\$Computer\" + $SysDrive + "\Program Files (x86)"
if (test-path ("\\$Computer\" + $SysDrive))
{
if (test-path $x64)
{
New-Object PSObject -Property #{
Hostname=$Computer
OSArchitecture="64-bit"
SysDrive=$SysDrive
OSVersion=$OSVersion
WinDir=$WinDir
}
}
elseif (!(test-path $x64))
{
New-Object PSObject -Property #{
Hostname=$Computer
OSArchitecture="32-bit"
SysDrive=$SysDrive
OSVersion=$OSVersion
WinDir=$WinDir
}
}
}
else {"Something wrong determining the System Drive"}
}
} | select Hostname,OSArchitecture,SysDrive,WinDir,OSVersion
}#Process
End
{
}#End
}#Get-OSArchitecture
My problem begins below.
$string1 = "SALES-DENNY"
Get-OSArchitecture $string1
The above fails.
The below works.
Get-OSArchitecture "SALES-DENNY"
I expect the function to give out the correct architecture of the computer with the name "SALES-DENNY" but if I don't put it in as a string I always get a blank result.
Although it should not matter if you give the computername as hardcoded string or as a name or IP in a variable, I do believe you could improve the function by not testing the Program Files (x86) directory.
Instead, there are two other WMI functions you can rely on to get the 'bitness' of the OS:
function Get-OSArchitecture {
[CmdletBinding()]
param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
[string[]]$ComputerName = $env:COMPUTERNAME
)
process {
foreach ($computer in $ComputerName) {
Write-Verbose "Retrieving info for computer '$computer'"
$info = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer |
Select-Object #{Name = 'HostName'; Expression = { $_.PSComputerName}},
OSArchitecture,
#{Name = 'SysDrive'; Expression = { '{0}$' -f ($_.SystemDrive).Substring(0,1) }},
#{Name = 'WinDir'; Expression = { $_.WindowsDirectory}},
#{Name = 'OSVersion'; Expression = { $_.Version }}
if ($info.OSArchitecture) {
$info.OSArchitecture = '{0}-bit' -f ($info.OSArchitecture -replace '\D+','')
}
else {
$info.OSArchitecture = '{0}-bit' -f (Get-WmiObject -Class Win32_Processor -ComputerName $computer).AddressWidth
# or do:
# $info.OSArchitecture = '{0}-bit' -f (((Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer).SystemType -replace '\D+', '') -replace '86', '32')
}
# emit info
$info
}
}
}
Hope that helps

Local Admins report not showing domain groups

I'm trying to get the following script to export into a csv all of the local admins members and domain groups on a group of servers. It works fine to export the local admins, but I noticed that it doesn't export domain groups (ie: I have a Domain Admins group that's in the local administrators group and it doesn't show in the csv).
This is the code I have, any help would be appreciated:
param(
[parameter(Position=0,ValueFromPipeline=$true)]
$ComputerName=[Net.Dns]::GetHostName(),
[System.Management.Automation.PSCredential] $Credential,
[UInt32] $BlockSize=50
)
begin {
$WMIEnumOpts = new-object System.Management.EnumerationOptions
$WMIEnumOpts.BlockSize = $BlockSize
function Get-LocalAdminGroupMember {
param(
[String] $computerName,
[System.Management.Automation.PSCredential] $credential
)
$params = #{
"Class" = "Win32_Group"
"ComputerName" = $computerName
"Filter" = "LocalAccount=TRUE and SID='S-1-5-32-544'"
}
if ( $credential ) {
if ( $computerName -eq [Net.Dns]::GetHostName() ) {
Write-Warning "The -Credential parameter is ignored for the current computer."
}
else {
$params.Add("Credential", $credential)
}
}
Get-WmiObject #params | ForEach-Object {
$groupName = $_.Name
$_.GetRelated("Win32_Account","Win32_GroupUser","","",
"PartComponent","GroupComponent",$false,$WMIEnumOpts) | Select-Object `
#{Name="ComputerName"; Expression={$_.__SERVER}},
#{Name="Name"; Expression={$groupName}},
#{Name="Member"; Expression={$_.Caption -replace "^$($_.__SERVER)\\", ""}},
#{Name="Type"; Expression={$_.__CLASS}}
}
}
}
process {
$Filename = PATH HERE
$OutFileName = "C:\temp\admins.csv"
Get-Content $Filename | Foreach-Object {Get-LocalAdminGroupMember -computerName $_ | Select-Object * | Export-csv -NoType $OutFileName -Append}
Ah, the joys of trying to access network resources from a remote computer. You're going to lose anything that's a domain account doing what you're doing. It's jut how it works. The good news is that there's still a way to get the info you want, and you can even use Get-WmiObject to do it if you want. If you have not renamed the Administrators group (because really, who does that?), you can do this easily, but if you did and you have to look for the group by SID like you are above then you'll have to query the remote server like you are, and make adjustments with the query below with the modified name that you get back. Here's what I'd recommend doing, using the Win32_GroupUser class instead:
Get-WmiObject -ComputerName $Server -Query "SELECT * FROM win32_GroupUser WHERE GroupComponent = ""Win32_Group.Domain='$computerName',Name='Administrators'"""
To put it in place of what you have for your function, it could look something like this:
function Get-LocalAdminGroupMember {
param(
[String] $computerName,
[System.Management.Automation.PSCredential] $credential
)
$params = #{
"ComputerName" = $computerName
"Query" = "SELECT * FROM win32_GroupUser WHERE GroupComponent = ""Win32_Group.Domain='$computerName',Name='Administrators'"""
}
if ( $credential ) {
if ( $computerName -eq [Net.Dns]::GetHostName() ) {
Write-Warning "The -Credential parameter is ignored for the current computer."
}
else {
$params.Add("Credential", $credential)
}
}
Get-WmiObject #params |
Where{$_.PartComponent -match ':(.+?)\.Domain="(.+?)",Name="(.+?)"'}|
ForEach{
[PSCustomObject]#{
"ComputerName"=$computerName
"Name"='Administrators'
"Member"=$Matches[2..3] -join '\' -replace "^$computerName\\"
"Type"=$Matches[1]
}
}
}

PowerShell Printer port property hostaddress not always populated

We're trying to create a list of all the printers on a print server with their respective HostAddress for the shared port they use. To do this we created the following function:
Function Get-PrintersInstalledHC {
Param (
[Parameter(ValueFromPipeline)]
[Object[]]$Servers
)
Process {
foreach ($S in $Servers) {
Try {
if ($Printers = Get-Printer -ComputerName $S.Name -Full -EA Stop) {
$CimParams = #{
ClassName = 'Win32_PrinterConfiguration'
ComputerName = $S.Name
Property = '*'
ErrorAction = 'Stop'
}
$Details = Get-CimInstance #CimParams
$Ports = Get-CimInstance -ClassName Win32_TCPIPPrinterPort -ComputerName $S.Name -Property *
Foreach ($P in $Printers) {
Foreach($D in $Details) {
if ($P.Name -eq $D.Name) {
$Prop = #{
PortHostAddress = $Ports | Where {$_.Name -eq $P.PortName} |
Select -ExpandProperty HostAddress
DriverVersion = $D.DriverVersion
Collate = $D.Collate
Color = $D.Color
Copies = $D.Copies
Duplex = $D.Duplex
PaperSize = $D.PaperSize
Orientation = $D.Orientation
PrintQuality = $D.PrintQuality
MediaType = $D.MediaType
DitherType = $D.DitherType
RetrievalDate = (Get-Date -Format 'dd/MM/yyyy HH:mm')
}
$P | Add-Member -NotePropertyMembers $Prop -TypeName NoteProperty
Break
}
}
}
[PSCustomObject]#{
ComputerName = $S.Name
ComputerStatus = 'Ok'
RetrievalDate = (Get-Date -Format 'dd/MM/yyyy HH:mm')
Printers = $Printers
}
}
}
Catch {
if (Test-Connection $S.Name -Count 2 -EA Ignore) {
[PSCustomObject]#{
ComputerName = $S.Name
ComputerStatus = "ERROR: $($Error[0].Exception.Message)"
RetrievalDate = (Get-Date -Format 'dd/MM/yyyy HH:mm')
Printers = $null
}
}
else {
[PSCustomObject]#{
ComputerName = $S.Name
ComputerStatus = 'Offline'
RetrievalDate = (Get-Date -Format 'dd/MM/yyyy HH:mm')
Printers = $null
}
}
}
}
}
}
This function works fine in a mixed environment and gives us the full list of all the printers installed on a server with their properties. However, the property HostAddress (renamed to PortHostAddress in the function above) is not always populated.
This is also illustrated with the following code, as not all printers are in the output:
Get-WmiObject Win32_Printer -ComputerName $PrintServer | ForEach-Object {
$Printer = $_.Name
$Port = $_.PortName
Get-WmiObject Win32_TCPIpPrinterPort -ComputerName $PrintServer | where {$_.Name -eq $Port} |
select #{Name="PrinterName";Expression={$Printer}}, HostAddress
}
For 90% of all printers the HostAddress can be found with this code. But sometimes it can't be found and the field stays empty because there is no match between the Name and the PortName.
Is there a better way of retrieving this property that works a 100% of the time?
Since the additional data states the problem ports are using drivers different from Microsoft's TCP/IP printer port driver, parsing these ports' addresses would require interacting with the drivers, this is dependant on the driver in question. So skip it, or convert a remote port to Microsoft's "Standard TCP/IP port" if possible. HP printers are easily converted, WSD printers can be converted by creating a TCP/IP port with the IP address of a WSD printer and assigning a static IP address on that printer, and about the same procedure could work with "Advanced TCP/IP port"s. The ports that are labeled "Local" ports are software-based, and you can use the host's IP address in place of missed PortHostAddress.

Displaying array properties for custom PSObjects

I'm pretty new to PowerShell, so to learn the ropes better, I'm working on a Powershell function to return some basic overview information on computers in our network. I've gotten just about everything that I'm looking for, but I don't know how to display all results for arrays returned by the WMI queries for things like hard disks or MAC addresses.
For example, right now I'm using the WMI query "DHCPEnabled = TRUE" to detect active NICs and retrieve their MAC addresses - but on a laptop, it's theoretically possible that query could return both a wired and wireless NIC.
The output of this command would then display the custom PSObject that I create, but in the resultant PSObject, the property MACAddress will display blank. The results are there, and I could get to them via the pipeline or a Select-Object, but I don't know how to save them for a report or otherwise "prettify" them.
Here's the working function I have now, which makes an awful assumption that the first result returned is the only one I care about. Again, in this example, this is mostly a concern for hard disks and for MAC addresses, but I'd like to understand the concept behind it for future reference.
Function Get-PCInfo
{
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)]
[Alias("CName")]
[string[]] $ComputerName
)
foreach($cName in $ComputerName)
{
Write-Verbose "Testing connection to $cName"
If (Test-Connection -ComputerName $cName -BufferSize 16 -Quiet)
{
Write-Verbose "Connection successful."
Write-Verbose "Obtaining WMI objects from $cName"
$cs = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $cName
$csp = Get-WMIObject -Class Win32_ComputerSystemProduct -ComputerName $cName
$os = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $cName
$bios = Get-WMIObject -Class Win32_BIOS -ComputerName $cName
$cpu = Get-WMIObject -Class Win32_Processor -ComputerName $cName
$hdd = Get-WMIObject -Class Win32_LogicalDisk -Filter 'DeviceID = "C:"' -ComputerName $cName
$network = Get-WMIObject -Class Win32_NetworkAdapterConfiguration -Filter 'DHCPEnabled = True' -ComputerName $cName
if ($hdd -is [System.array])
{
Write-Verbose "Multiple hard drives detected; using first result"
$hddResult = $hdd[0]
} else {
Write-Verbose "Single hard drive detected"
$hddResult = $hdd
}
if ($network -is [System.array])
{
Write-Verbose "Multiple network cards detected; using first result"
$networkResult = $network[0]
} else {
Write-Verbose "Single network card detected"
$networkResult = $network
}
Write-Verbose "Creating output table"
$props = #{'Name' = $cs.Name;
'OSVersion' = $os.Version;
'ServicePack' = $os.ServicePackMajorVersion;
'HardDiskSize' = $hddResult.Size;
'SerialNumber' = $bios.serialNumber;
'Model' = $cs.Model;
'Manufacturer' = $cs.Manufacturer;
'Processor' = $cpu.Name;
'RAM' = $cs.TotalPhysicalMemory;
'MACAddress' = $networkResult.MACAddress}
Write-Verbose "Creating output object from table"
$result = New-Object -TypeName PSObject -Property $props
Write-Verbose "Outputting result"
$resultArray += #($result)
} else {
Write-Verbose "Connection failure"
$resultArray += #($null)
}
}
Write-Output $resultArray
}
Here's an example run, for some more clarity. The data is fake, but this is the format of the result:
PS> Get-PCInfo localhost
SerialNumber : 12345
MACAddress :
RAM : 4203204608
Manufacturer : Computers, Inc.
Processor : Intel(R) Core(TM) i5-2400 CPU # 3.10GHz
HardDiskSize : 500105736192
OSVersion : 6.2.9200
Name : PC1
Model: : Super Awesome Computer
ServicePack : 0
I'd like to send this to ConvertTo-HTML or something to make a nice-looking report, but because MACAddress is blank, I can't make anything nice out of it. What I'd like to see is something like this:
SerialNumber : 12345
MACAddress[0] : 00-11-22-33-44-55
MACAddress[1] : 88-99-AA-BB-CC-DD
...
HardDiskSize[0]: 500105736192
HardDiskSize[1]: 500105736192
I'm not quite sure I understand? It depends on how you want them to output. You can do it in many ways. An example for HDDs and MAC addresses:
....
'HardDiskSize' = ($hdd | % { "HDD $($_.DeviceID) - $($_.Size)" }) -join "`n"
....
'MACAddress' = ($networkResult | Select-Object -ExpandProperty MACAddress) -join "`n"
}
You can try this (untested). Copy and paste the edited parts back:
$hdd = #(Get-WMIObject -Class Win32_LogicalDisk -Filter 'DeviceID = "C:"' -ComputerName $cName)
$network = #(Get-WMIObject -Class Win32_NetworkAdapterConfiguration -Filter 'DHCPEnabled = True' -ComputerName $cName)
$props = #{'Name' = $cs.Name;
'OSVersion' = $os.Version;
'ServicePack' = $os.ServicePackMajorVersion;
'SerialNumber' = $bios.serialNumber;
'Model' = $cs.Model;
'Manufacturer' = $cs.Manufacturer;
'Processor' = $cpu.Name;
'RAM' = $cs.TotalPhysicalMemory;
Write-Verbose "Creating output object from table"
$result = New-Object -TypeName PSObject -Property $props
# Add MAC addresses
for ($i = 0; $i -lt $network.Count; $i++) {
Add-Member -InputObject $result -MemberType NoteProperty -Name "MACAddress[$i]" -Value $network[$i].MACAddress
}
# Add HDDs
for ($i = 0; $i -lt $hdd.Count; $i++) {
Add-Member -InputObject $result -MemberType NoteProperty -Name "HardDiskSize[$i]" -Value $hdd[$i].Size
}