How to get the content of a file during NuGet package install - nuget-package

I have a nuget package solution which installs just fine. I now need to modify the target project's Properties\AssemblyInfo.cs file to add some code.
I have an Install.ps1 script so I'm adding my powershell script to this. As I'm building it up as I go, what it does at the moment is this:
param($installPath, $toolsPath, $package, $project)
$content = Get-Content $project.ProjectItems.Item("Properties\AssemblyInfo.cs")
The error it is giving me is this:
Value does not fall within the expected range.At
C:\git\Testing\packages\Standards.Testing.1.0.6694.30974-beta\tools\Install.ps1:2
char:1
+ $content = Get-Content $project.ProjectItems.Item("Properties\Assembl ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException
The intent is to load the content of the AssemblyInfo.cs file and check it for certain content, then modify it and write it back.
What I don't understand is why it won't read the content of that file into a variable.

The problem was that I was incorrectly trying to reference the path of the AssemblyInfo.cs file. I didn't realise that the parameters to the script were providing everything I need and that other posts have referenced a scary-looking class which contains all the required information.
SO containing information about script parameters:
Need PowerShell Script in NuGet to install selected DLLs from Package into a VS Project
Linked from that post is this page which details the available information about a nuget install:
https://learn.microsoft.com/en-us/dotnet/api/envdte.dte?redirectedfrom=MSDN&view=visualstudiosdk-2017
My script now looks like this:
param($installPath, $toolsPath, $package, $project)
#Update the AssemblyInfo.cs if it has not been updated before
function Get-Append-String {
$text = ''
$args[0] | ForEach-Object -Process {
$text += $_ + "`n"
}
return $text
}
function Get-Append {
$text = ''
$args | ForEach-Object -Process {
$text += $_
}
return $text
}
function Get-Contains {
$text = Get-Append-String $args[0]
return ($text -like $args[1])
}
$query = "*using Xunit;*"
$xunit = "using Xunit;`n"
$comment = "`n// xUnit configuraiton...`n// MaxParallelThreads limits the number of threads which xUnit will use to run tests`n[assembly: CollectionBehavior(MaxParallelThreads = 8)]`n"
$path = $project.FullName + '\..\Properties\AssemblyInfo.cs'
$content = Get-Content -Path $path
$content = Get-Append-String $content
if ( ($content -like $query) -eq $false ) {
$content = $xunit + $content + $comment
Set-Content -Path $path -Value $content
}

Related

How to search for a string in multiple text files in an active running log

I am trying to search for a string in multiple text files to trigger an event. The log file is being actively added to by a program. The following script successfully achieves that goal, but it only works for one text file at a time:
$PSDefaultParameterValues = #{"Get-Date:format"="yyyy-MM-dd HH:mm:ss"}
Get-Content -path "C:\Log 0.txt" -Tail 1 -Wait | ForEach-Object { If ($_ -match 'keyword') {
Write-Host "Down : $_" -ForegroundColor Green
Add-Content "C:\log.txt" "$(get-date) down"
Unfortunately it means I have to run 3 instances of this script to search the 3 log files (C:\log 0.txt, C:\log 1.txt and C:'log 2.txt).
What I want to do is run one powershell script to search for that string across all three text files and not three.
I tried using a wildcard in the path ("C:\log*.txt)
I also tried adding a foreach loop:
$PSDefaultParameterValues = #{"Get-Date:format"="yyyy-MM-dd HH:mm:ss"}
$LogGroup = ('C:\log 0.txt', 'C:\Log 1.txt', 'C:\Log 2.txt')
ForEach ($log in $LogGroup) {
Get-Content $log -Tail 1 -Wait | ForEach-Object { If ($_ -match 'keyword') {
Write-Host "Down: $_" -ForegroundColor Green
Add-Content -path "C:\log.txt" "$(get-date) down"
Add-Content -path "C:\log.txt" "$(get-date) down"
}
}
}
This got me no errors but it also didn't work.
I saw others use Get-ChildItem instead of Get-Content but since this worked with one file... shouldn't it work with multiple? I assume it's my lack of scripting ability. Any help would be appreciated. Thanks.
This is how you can apply the same logic you already have for one file but for multiple logs at the same time, the concept is to spawn as many PowerShell instances as log paths there are in the $LogGroup array. Each instance is assigned and will be monitoring 1 log path and when the keyword is matched it will append to the main log file.
The instances are assigned the same RunspacePool, this help us initialize all with a SemaphoreSlim instance which help us ensure thread safety (only 1 thread can write to the main log at a time).
using namespace System.Management.Automation.Runspaces
using namespace System.Threading
# get the log files here
$LogGroup = ('C:\log 0.txt', 'C:\Log 1.txt', 'C:\Log 2.txt')
# this help us write to the main log file in a thread safe manner
$lock = [SemaphoreSlim]::new(1, 1)
# define the logic used for each thread, this is very similar to the
# initial script except for the use of the SemaphoreSlim
$action = {
param($path)
$PSDefaultParameterValues = #{ "Get-Date:format" = "yyyy-MM-dd HH:mm:ss" }
Get-Content $path -Tail 1 -Wait | ForEach-Object {
if($_ -match 'down') {
# can I write to this file?
$lock.Wait()
try {
Write-Host "Down: $_ - $path" -ForegroundColor Green
Add-Content "path\to\mainLog.txt" -Value "$(Get-Date) Down: $_ - $path"
}
finally {
# release the lock so other threads can write to the file
$null = $lock.Release()
}
}
}
}
try {
$iss = [initialsessionstate]::CreateDefault2()
$iss.Variables.Add([SessionStateVariableEntry]::new('lock', $lock, $null))
$rspool = [runspacefactory]::CreateRunspacePool(1, $LogGroup.Count, $iss, $Host)
$rspool.ApartmentState = [ApartmentState]::STA
$rspool.ThreadOptions = [PSThreadOptions]::UseNewThread
$rspool.Open()
$res = foreach($path in $LogGroup) {
$ps = [powershell]::Create($iss).AddScript($action).AddArgument($path)
$ps.RunspacePool = $rspool
#{
Instance = $ps
AsyncResult = $ps.BeginInvoke()
}
}
# block the main thread
do {
$id = [WaitHandle]::WaitAny($res.AsyncResult.AsyncWaitHandle, 200)
}
while($id -eq [WaitHandle]::WaitTimeout)
}
finally {
# clean all the runspaces
$res.Instance.ForEach('Dispose')
$rspool.ForEach('Dispose')
}

How to output hash table query result into Out-GridView?

I wish to export a hashtable result into Out-GridView using the Powershell.
The purpose of the below script is to export the Azure VM tags to Out-GridView, it throws error like the below blank result:
Error on the console:
Out-GridView : Syntax error in PropertyPath 'Syntax error in Binding.Path '[ Product] ' ... '(Tag)'.'.
At line:46 char:19
+ $Output | Out-GridView #Export-Csv -Path c:\temp\1a.csv -appe ...
+ ~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Out-GridView], InvalidOperationException
+ FullyQualifiedErrorId : ManagementListInvocationException,Microsoft.PowerShell.Commands.OutGridViewCommand
This is the actual script which was executed under the Global Administrator role:
<#
.AUTHOR: https://stackoverflow.com/users/13390556/lukasz-g
#>
$Subscription = Get-AzSubscription | Out-GridView -Title 'Select subscription' -OutputMode 'Multiple'
# Initialise output array
$Output = #()
if ($Subscription) {
foreach ($item in $Subscription) {
$item | Select-AzSubscription
# Collect all the resources or resource groups (comment one of below)
$Resource = Get-AzResource
#$Resource = Get-AzResourceGroup
# Obtain a unique list of tags for these groups collectively
$UniqueTags = $Resource.Tags.GetEnumerator().Keys | Get-Unique -AsString | Sort-Object | Select-Object -Unique | Where-Object { $_ -notlike "hidden-*" }
# Loop through the resource groups
foreach ($ResourceGroup in $Resource) {
# Create a new ordered hashtable and add the normal properties first.
$RGHashtable = New-Object System.Collections.Specialized.OrderedDictionary
$RGHashtable.Add("Name", $ResourceGroup.ResourceGroupName)
$RGHashtable.Add("Location", $ResourceGroup.Location)
$RGHashtable.Add("Id", $ResourceGroup.ResourceId)
$RGHashtable.Add("ResourceType", $ResourceGroup.ResourceType)
# Loop through possible tags adding the property if there is one, adding it with a hyphen as it's value if it doesn't.
if ($ResourceGroup.Tags.Count -ne 0) {
$UniqueTags | Foreach-Object {
if ($ResourceGroup.Tags[$_]) {
$RGHashtable.Add("[$_] (Tag)", $ResourceGroup.Tags[$_])
}
else {
$RGHashtable.Add("[$_] (Tag)", "-")
}
}
}
else {
$UniqueTags | Foreach-Object { $RGHashtable.Add("[$_] (Tag)", "-") }
}
# Update the output array, adding the ordered hashtable we have created for the ResourceGroup details.
$Output += New-Object psobject -Property $RGHashtable
}
# Sent the final output to CSV
$Output | Out-GridView #Export-Csv -Path c:\temp\1a.csv -append -NoClobber -NoTypeInformation -Encoding UTF8 -Force
}
}
$RGHashtable.Add("[$_] (Tag)"
In above code, You are trying to add something like below :
In the output
Removed everthing and I tested with simple statements
$Output = #()
$RGHashtable = New-Object System.Collections.Specialized.OrderedDictionary
$RGHashtable.Add("[Testing] (Name)", "Temporary")
$Output += New-Object psobject -Property $RGHashtable
$Output | Out-GridView
I was provided with the same error.
After couple of testing, understood the error only occurs when there is a combination "[SomeString](SomeString)" --- [...](....) in the string.
The Out-GridView is trying to parse the "[<SomeString>](<SomeString>)" and hence the error.
You could try any 1 of the below combination in your code :
$RGHashtable.Add("[$_] [Tag]", $ResourceGroup.Tags[$_])
OR
$RGHashtable.Add("{$_} (Tag)", $ResourceGroup.Tags[$_])
OR
$RGHashtable.Add("[$_] [Tag]", $ResourceGroup.Tags[$_])
This should resolve your issue.
you will have change in 3 instances in your code if I am not wrong.

Automatically version Asp.net Core Web App

I have a web application in Asp.Net Core 2.0. In the csproj I have a version number with pattern 1.0.0.0. I would like when I compile with VSTS that the pattern becomes 1.0.0.$Build.Id, but I cannot find a way to do this.
I tried the Update Assembly Info VSTS extension this task but it does not work:
There are many extensions in marketplace that can update assembly info, such as Assembly Info.
You also can do it through PowerShell script with PowerShell task: Auto assembly versioning in Visual Studio Team Services (or VSTS) build.
Param
(
[Parameter(Mandatory=$true)]
[string]$productVersion
)
$buildNumber = $env:BUILD_BUILDNUMBER
if ($buildNumber -eq $null)
{
$buildIncrementalNumber = 0
}
else
{
$splitted = $buildNumber.Split('.')
$buildIncrementalNumber = $splitted[$splitted.Length - 1]
}
$SrcPath = $env:BUILD_SOURCESDIRECTORY
Write-Verbose "Executing Update-AssemblyInfoVersionFiles in path $SrcPath for product version Version $productVersion" -Verbose
$AllVersionFiles = Get-ChildItem $SrcPath AssemblyInfo.cs -recurse
$versions = $productVersion.Split('.')
$major = $versions[0]
$minor = $versions[1]
$patch = $versions[2]
$assemblyVersion = $productVersion
$assemblyFileVersion = "$major.$minor.$patch.$buildIncrementalNumber"
$assemblyInformationalVersion = $productVersion
Write-Verbose "Transformed Assembly Version is $assemblyVersion" -Verbose
Write-Verbose "Transformed Assembly File Version is $assemblyFileVersion" -Verbose
Write-Verbose "Transformed Assembly Informational Version is $assemblyInformationalVersion" -Verbose
foreach ($file in $AllVersionFiles)
{
(Get-Content $file.FullName) |
%{$_ -replace 'AssemblyVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', "AssemblyVersion(""$assemblyVersion"")" } |
%{$_ -replace 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', "AssemblyFileVersion(""$assemblyFileVersion"")" } |
%{$_ -replace 'AssemblyInformationalVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)', "AssemblyInformationalVersion(""$assemblyInformationalVersion"")" } |
Set-Content $file.FullName -Force
}
return $assemblyFileVersion

Splitting output of a string into separate strings

I've been working on a powershell script and it's been really boggling my mind. There are 2 parts to the script.
First part is a function that gets all servers in a domain. We have 4 different domains, so I check each one individually and output the result.
Second part is a function that outputs the software on a specific remote machine. In my case, the output from the function above will be seeded into this function to see if a server has a particular piece of software installed.
The function that searches the software works properly. The function that I am getting an output of all the servers is what I am having trouble with.
The issue is, that when I output the list of servers (the output is correct), it outputs everything into a single large multiline string...
For example lets say I have 5 servers: (ServerA, ServerB, ServerC, ServerD, ServerE).
When I run the code I will get an output of all the servers for each domain like so:
TestA.com
ServerA
ServerB
ServerC
ServerD
ServerE
TestB.com
ServerA
ServerB
ServerC
ServerD
ServerE
TestC.com
ServerA
ServerB
ServerC
ServerD
ServerE
TestD.com
ServerA
ServerB
ServerC
ServerD
ServerE
However each domain output is all 1 string, so I can't seed it into the function to check software because it's trying to find it in "ServerA,ServerB,ServerC,ServerD,ServerE", instead of each server individually.
I hope this makes sense. Here is my code to get the list of servers.
#Clear Screen
CLS
function Get-Servers
{
#Variables
[array]$MyDomains="TestA.com","TestB.com","TestC.com","TestD.com"
[array]$MySearchBase="dc=TestA,dc=com","dc=TestB,dc=com","dc=TestC,dc=com","dc=TestD,dc=com"
for($i=0; $i -lt $MyDomains.Count; $i++)
{
Write-Output $($MyDomains[$i])
$MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string
foreach ($MyServer in $MyServers)
{
$MyServer
pause
}
}
}
#Get list of servers
Get-Servers
How can I get the output for each server individually to be stored in the "$MyServer" variable?
EDIT:
Here is my function to find remote software
function Get-RemoteRegistryProgram
{
<#
.Synopsis
Uses remote registry to read installed programs
.DESCRIPTION
Use dot net and the registry key class to query installed programs from a
remote machine
.EXAMPLE
Get-RemoteRegistryProgram -ComputerName Server1
#>
[CmdletBinding()]
Param
(
[Parameter(
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string[]]
$ComputerName = $env:COMPUTERNAME
)
begin
{
$hives = #(
[Microsoft.Win32.RegistryHive]::LocalMachine,
[Microsoft.Win32.RegistryHive]::CurrentUser
)
$nodes = #(
"Software\Microsoft\Windows\CurrentVersion\Uninstall",
"Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
}
process
{
$ComputerName
forEach ($computer in $ComputerName)
{
forEach($hive in $hives)
{
try
{
$registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive,$computer)
}
catch
{
throw $PsItem
}
forEach($node in $nodes)
{
try
{
$keys = $registry.OpenSubKey($node).GetSubKeyNames()
forEach($key in $keys)
{
$displayname = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayName')
if($displayname)
{
$installedProgram = #{
# ComputerName = $computer
DisplayName = $displayname
# Version = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayVersion')
}
New-Object -TypeName PSObject -Property $installedProgram
}
}
}
catch
{
$orginalError = $PsItem
Switch($orginalError.FullyQualifiedErrorId)
{
'InvokeMethodOnNull'
{
#key maynot exists
}
default
{
throw $orginalError
}
}
}
}
}
}
}
end
{
}
}
EDIT 2:
If I modify my server function like so:
for($i=0; $i -lt $MyDomains.Count; $i++)
{
Write-Output $($MyDomains[$i])
$MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders
foreach ($MyServer in $MyServers)
{
Get-RemoteRegistryProgram -ComputerName $MyServer
}
}
I get the following error:
Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Exception calling "OpenRemoteBaseKey" with "2" argument(s): "The network path was not found.
"
At line:47 char:21
+ $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : IOException
Thank you in advance for any help!
Your code is converting the server names to a string
$MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string
The last part of that is out-string. Instead of piping to a format table and pushing it out as a string, keep the objects and use the properties in each object to get the names of each server.
I ended up rewriting some things and fixing my issue. To avoid the string issue, I export the results to a text file and then using get-content I read line by line from the text file and seeded each server to let me know which servers have the software I need. Here is the end result.
#Clear Screen
CLS
function Get-RemoteRegistryProgram
{
<#
.Synopsis
Uses remote registry to read installed programs
.DESCRIPTION
Use dot net and the registry key class to query installed programs from a
remote machine
.EXAMPLE
Get-RemoteRegistryProgram -ComputerName Server1
#>
[CmdletBinding()]
Param
(
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)][string]$ComputerName = $env:COMPUTERNAME,
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=1)][string]$SoftwareName
)
begin
{
$hives = #(
[Microsoft.Win32.RegistryHive]::LocalMachine,
[Microsoft.Win32.RegistryHive]::CurrentUser
)
$nodes = #(
"Software\Microsoft\Windows\CurrentVersion\Uninstall",
"Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
}
process
{
$ComputerName
$skip = $false
forEach ($computer in $ComputerName)
{
forEach($hive in $hives)
{
try
{
$registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive,$computer)
}
catch
{
$skip = $true
}
if($skip -eq $false)
{
forEach($node in $nodes)
{
try
{
$keys = $registry.OpenSubKey($node).GetSubKeyNames()
forEach($key in $keys)
{
$displayname = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayName')
#Modified by James
if(($displayname) -like "*$SoftwareName*")
{
$displayname + "`t" + $computer >> c:\scripts\sysaidServers.txt
}
<# Modified by James
if($displayname)
{
$installedProgram = #{
# ComputerName = $computer
DisplayName = $displayname
# Version = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayVersion')
}
New-Object -TypeName PSObject -Property $installedProgram
}
#>
}
}
catch
{
<#
$orginalError = $PsItem
Switch($orginalError.FullyQualifiedErrorId)
{
'InvokeMethodOnNull'
{
#key maynot exists
}
default
{
throw $orginalError
}
}
#>
}
}
}
}
}
}
end
{
}
}
#Output the servers to a txt file
function Get-Servers
{
param ([Parameter( Mandatory=$true)][string]$SaveFile)
#Variables
[array]$MyDomains="DomainA.com","DomainB.com","DomainC.com","DomainD.com"
[array]$MySearchBase="dc=DomainA,dc=com","dc=DomainB,dc=com","dc=DomainC,dc=com","dc=DomainD,dc=com"
for($i=0; $i -lt $MyDomains.Count; $i++)
{
#I only want servers running Windows Server OS
$MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string
#Remove all whitespace and export to txt file
$MyServers.Trim() -replace (' ', '') >> $SaveFile
}
}
function CheckServerSoftware
{
param ([Parameter( Mandatory=$true)][string]$SaveFile)
Get-Content $SaveFile | ForEach-Object {
if($_ -match $regex)
{
$computer = $_.ToString()
Get-RemoteRegistryProgram -ComputerName $computer.Trim() $SoftwareName
Write-Output ""
}
}
}
#Path to where our exported server list is
$SaveFile = "c:\scripts\servers.txt"
$SoftwareName = "SysAid"
#If the file already exists, remove it
Remove-Item $SaveFile
#Create the text file with servers
Get-Servers $SaveFile
#Import our server list and check software on each server
CheckServerSoftware $SaveFile

Display all sites and bindings in PowerShell

I am documenting all the sites and binding related to the site from the IIS. Is there an easy way to get this list through a PowerShell script rather than manually typing looking at IIS?
I want the output to be something like this:
Site Bindings
TestSite www.hello.com
www.test.com
JonDoeSite www.johndoe.site
Try this:
Import-Module Webadministration
Get-ChildItem -Path IIS:\Sites
It should return something that looks like this:
Name ID State Physical Path Bindings
---- -- ----- ------------- --------
ChristophersWeb 22 Started C:\temp http *:8080:ChristophersWebsite.ChDom.com
From here you can refine results, but be careful. A pipe to the select statement will not give you what you need. Based on your requirements I would build a custom object or hashtable.
Try something like this to get the format you wanted:
Get-WebBinding | % {
$name = $_.ItemXPath -replace '(?:.*?)name=''([^'']*)(?:.*)', '$1'
New-Object psobject -Property #{
Name = $name
Binding = $_.bindinginformation.Split(":")[-1]
}
} | Group-Object -Property Name |
Format-Table Name, #{n="Bindings";e={$_.Group.Binding -join "`n"}} -Wrap
If you just want to list all the sites (ie. to find a binding)
Change the working directory to "C:\Windows\system32\inetsrv"
cd c:\Windows\system32\inetsrv
Next run "appcmd list sites" (plural) and output to a file. e.g c:\IISSiteBindings.txt
appcmd list sites > c:\IISSiteBindings.txt
Now open with notepad from your command prompt.
notepad c:\IISSiteBindings.txt
The most easy way as I saw:
Foreach ($Site in get-website) { Foreach ($Bind in $Site.bindings.collection) {[pscustomobject]#{name=$Site.name;Protocol=$Bind.Protocol;Bindings=$Bind.BindingInformation}}}
Try this
function DisplayLocalSites
{
try{
Set-ExecutionPolicy unrestricted
$list = #()
foreach ($webapp in get-childitem IIS:\Sites\)
{
$name = "IIS:\Sites\" + $webapp.name
$item = #{}
$item.WebAppName = $webapp.name
foreach($Bind in $webapp.Bindings.collection)
{
$item.SiteUrl = $Bind.Protocol +'://'+ $Bind.BindingInformation.Split(":")[-1]
}
$obj = New-Object PSObject -Property $item
$list += $obj
}
$list | Format-Table -a -Property "WebAppName","SiteUrl"
$list | Out-File -filepath C:\websites.txt
Set-ExecutionPolicy restricted
}
catch
{
$ExceptionMessage = "Error in Line: " + $_.Exception.Line + ". " + $_.Exception.GetType().FullName + ": " + $_.Exception.Message + " Stacktrace: " + $_.Exception.StackTrace
$ExceptionMessage
}
}
function Get-ADDWebBindings {
param([string]$Name="*",[switch]$http,[switch]$https)
try {
if (-not (Get-Module WebAdministration)) { Import-Module WebAdministration }
Get-WebBinding | ForEach-Object { $_.ItemXPath -replace '(?:.*?)name=''([^'']*)(?:.*)', '$1' } | Sort | Get-Unique | Where-Object {$_ -like $Name} | ForEach-Object {
$n=$_
Get-WebBinding | Where-Object { ($_.ItemXPath -replace '(?:.*?)name=''([^'']*)(?:.*)', '$1') -like $n } | ForEach-Object {
if ($http -or $https) {
if ( ($http -and ($_.protocol -like "http")) -or ($https -and ($_.protocol -like "https")) ) {
New-Object psobject -Property #{Name = $n;Protocol=$_.protocol;Binding = $_.bindinginformation}
}
} else {
New-Object psobject -Property #{Name = $n;Protocol=$_.protocol;Binding = $_.bindinginformation}
}
}
}
}
catch {
$false
}
}
I found this page because I needed to migrate a site with many many bindings to a new server. I used some of the code here to generate the powershell script below to add the bindings to the new server. Sharing in case it is useful to someone else:
Import-Module WebAdministration
$Websites = Get-ChildItem IIS:\Sites
$site = $Websites | Where-object { $_.Name -eq 'site-name-in-iis-here' }
$Binding = $Site.bindings
[string]$BindingInfo = $Binding.Collection
[string[]]$Bindings = $BindingInfo.Split(" ")
$i = 0
$header = ""
Do{
[string[]]$Bindings2 = $Bindings[($i+1)].Split(":")
Write-Output ("New-WebBinding -Name `"site-name-in-iis-here`" -IPAddress " + $Bindings2[0] + " -Port " + $Bindings2[1] + " -HostHeader `"" + $Bindings2[2] + "`"")
$i=$i+2
} while ($i -lt ($bindings.count))
It generates records that look like this:
New-WebBinding -Name "site-name-in-iis-here" -IPAddress "*" -Port 80 -HostHeader www.aaa.com
I found this question because I wanted to generate a web page with links to all the websites running on my IIS instance. I used Alexander Shapkin's answer to come up with the following to generate a bunch of links.
$hostname = "localhost"
Foreach ($Site in get-website) {
Foreach ($Bind in $Site.bindings.collection) {
$data = [PSCustomObject]#{
name=$Site.name;
Protocol=$Bind.Protocol;
Bindings=$Bind.BindingInformation
}
$data.Bindings = $data.Bindings -replace '(:$)', ''
$html = "" + $data.name + ""
$html.Replace("*", $hostname);
}
}
Then I paste the results into this hastily written HTML:
<html>
<style>
a { display: block; }
</style>
{paste PowerShell results here}
</body>
</html>

Resources