public/Products/Appliances.ps1
#Meraki Appliance Functions using namespace System.Management function Get-MerakiNetworkApplianceContentFilteringCategories() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id ) $Uri = "{0}/networks/{1}/appliance/contentFiltering/categories" -f $BaseURI, $id $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Returns the content filtering categories for this network.* .PARAMETER id The Network ID. .OUTPUTS An array of content filtering categories. .NOTES Filtering category IDs are different between MX devices. You cannot use category IDs from an MX84 to set categories on an MX100. It is best practive to pull the list of categories from the device before attempting to set any new categories. #> } Set-Alias GMNetAppCFCats -Value Get-MerakiNetworkApplianceContentFilteringCategories -Option ReadOnly <# .Description Retrieve content filtering Rules for a network #> function Get-MerakiNetworkApplianceContentFiltering() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$id ) $Uri = "{0}/networks/{1}/appliance/contentFiltering" -f $BaseURI, $id $headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Get the content filtering settings for this appliance. .PARAMETER id The network Id. .OUTPUTS An array of Meraki content filtering objects. #> } Set-Alias GMNetCF -Value Get-MerakiNetworkApplianceContentFiltering -Option ReadOnly function Update-MerakiNetworkApplianceContentFiltering() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id, [ValidateScript( { if ($ContentFilteringRules) { throw "The allowedURLPatterns parameter cannot be used with the ContentFilteringRules parameter." } elseif (-not $_) { throw "The allowedURLPatterns parameter is require if the ContentFilteringRules parameter is omitted." } elseif ((-not $blockedURLPatterns) -or (-not $blockedUrlCategories) -or (-not $urlCategoryListSize)) { throw "The allowedUrlPatterns parameter requires the blockedURLPatterns and blockedUrlCategories parameters " } else { $true } } )] [string[]]$allowedURLPatterns, [Parameter( Mandatory=$true, ParameterSetName = "values" )] [string[]]$blockedURLPatterns, [string[]]$blockedUrlCategories, [string]$urlCategoryListSize, [ValidateScript({$_ -and -not ($allowedURLPatterns -or $blockedUrlCategories -or $urlCategoryListSize)}, ErrorMessage="The parameter ContentFilteringRules cannot be used with the allowedURLPatterns, blockedURLPatterns, blockedURLCategories -or urlCategoriesList parameters")] [psObject]$ContentFilteringRules ) If ($ContentFilteringRules) { if ($allowedURLPatterns) { Write-Host "The Parameter AlloweeUrlPatterns cannot be used with" } } $Uri = "{0}/networks/{1}/appliance/contentFiltering" -f $BaseURI, $id $Headers = Get-Headers if ($ContentFilteringRules) { if ($ContentFilteringRules.allowedUrlPatterns) { $allowedURLPatterns = $ContentFilteringRules.allowedUrlPatterns } if ($ContentFilteringRules.blockedUrlPatterns) { $blockedURLPatterns = $ContentFilteringRules.blockedUrlPatterns } if ($ContentFilteringRules.urlCategoryListSize) { $urlCategoryListSize = $ContentFilteringRules.urlCategoryListSize } if ($ContentFilteringRules.blockedUrlCategories) { $ContentFilteringRules.blockedUrlCategories | ForEach-Object { $blockedUrlCategories += $_.Id } } } $properties = [ordered]@{} if ($allowedURLPatterns) {$properties.Add("allowedUrlPatterns", $allowedURLPatterns) } if ($blockedURLPatterns) {$properties.Add("blockedUrlPatterns", $blockedURLPatterns) } if ($urlCategoryListSize) {$properties.Add("urlCategoryListSize", $urlCategoryListSize) } if ($blockedUrlCategories) {$properties.Add("blockedUrlCategories", $blockedUrlCategories) } $psBody = [PSCustomObject]$properties $body = $psBody | ConvertTo-Json -Compress -Depth 6 try { $response = Invoke-RestMethod -Method PUT -Uri $Uri -Body $body -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Update the content filtering rules. .PARAMETER id The Network Id. .PARAMETER allowedURLPatterns An array of allowed URL patterns. .PARAMETER blockedURLPatterns AM array of blocked URL patterns. .PARAMETER blockedUrlCategories An array of blocked URL Categories. .PARAMETER urlCategoryListSize The list size of the category list. Note this parameter is not supported on MX100 and above devices. .PARAMETER ContentFilteringRules A Meraki content filtering rule object (not supported with other parameters). .OUTPUTS The updated Meraki content filtering object. .NOTES .EXAMPLE You must pull the Content Filtering Rules using the function Get-MerakiNetworkApplianceContentFiltering and then modify the properties of that object. Adding a new URL to the blocked URL Pattern PS> $cfr = Get-MerakiNetworks | Where-Object {$_.Name -like "Dallas} | Get-MerakiNetworkApplianceContentFiltering PS> $cfr.blockedUrlPatterns += "example.com" PS> Get-MerakiNetworks | Where-Object {$_.Name -like "Dallas"} | Update-MerakiNetworkApplianceContentFiltering -allowedUrlPatterns $cfr.allowedUrlPattern -blockedUrlPatterns $cfr.blockedUrlPatterns -blockedUrlCategories $cfr.blockedUrlCategories -urlCategoryListSize $cfr.urlCategoryListSize or PS > Get-MerakiNetworks | Where-Object {$_.like "Dallas"} | Update-MerakiNetworkApplianceContentFiltering -ContentFilteringRules $cfr .EXAMPLE Updating Templates If you have networks bound to templates, you should update the template and allow the template to trickle the changes down to the bound network. PS> $cfr = Get-MerakiOrganizationConfigTemplates | Where-object {$_.Name -eq "Org-Tremplate"} | Get-MerakiNetworkApplianceContentFiltering PS> $cfr.clockedUrlPatterns += "example.com" PS> Get-MerakiOrganizationConfigTemplates | Where-Object ($_.Name -eq "Org-Template"} Update-MerakiNetworkApplianceContentFiltering -ContentFilteringRules $cfr #> } Set-Alias -Name UMNetAppCF -value Update-MerakiNetworkApplianceContentFiltering -Option ReadOnly function Add-MerakiNetworkApplianceContentFilteringRules() { Param ( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [String]$Id, [String[]]$allowedURLPatterns, [String[]]$blockedURLPatterns ) Process { if ((-not $allowedURLPatterns) -and (-not $blockedURLPatterns) ) { Write-Host "You must provide al least one of the content filtering patterns" -ForegroundColor Red exit } $cfr = Get-MerakiNetworkApplianceContentFiltering -Id $Id if ($allowedURLPatterns) { $allowedURLPatterns | ForEach-Object { $cfr.allowedUrlPatterns += $_ } } If ($blockedURLPatterns) { $blockedURLPatterns | ForEach-Object { $cfr.blockedURLPatterns += $_ } } Update-MerakiNetworkApplianceContentFiltering -Id $Id -ContentFilteringRules $Cfr } <# .SYNOPSIS Add new URL patterns. .DESCRIPTION Add the provided allowed and blocked URL patterns to the content filtering rule. .PARAMETER Id The Network ID. .PARAMETER allowedURLPatterns An array of allowed URL patterns. .PARAMETER blockedURLPatterns An array of blocked URL patterns. .OUTPUTS The updated content filtering rules. .EXAMPLE Add sites to the allowed and blocked URL patterns. PS> $Network | Add-MerakiNetworkApplianceContentFilteringRule -allowedUrlPatterns "xtz.com" -blockedUrlPatterns "badsite.com" #> } Set-Alias -Name AddMNetAppCFR -Value Add-MerakiNetworkApplianceContentFilteringRules -Option ReadOnly function Remove-MerakiNetworkApplianceContentFilteringRules () { Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id, [string[]]$allowedURLPatterns, [string[]]$blockedURLPatterns ) Process { If ((-not $allowedURLPatterns) -and (-not $blockedURLPatterns)) { Write-Host "You must provide al least one fo the content filtering patterns" -ForegroundColor Red exit } $cfr = Get-MerakiNetworkApplianceContentFiltering -Id $id if ($allowedURLPatterns) { $AUPList = [System.Collections.ArrayList]::New($cfr.allowedUrlPatterns) $allowedURLPatterns | Foreach-Object { $AUPList.Remove($_) } $cfr.allowedUrlPatterns = $AUPList.ToArray() } if ($blockedURLPatterns) { $BUPList = [System.Collections.ArrayList]::New($cfr.blockedUrlPatterns) $blockedURLPatterns | ForEach-Object { $BUPList.remove($_) } $cfr.blockedUrlPatterns = $BUPList.ToArray() } Update-MerakiNetworkApplianceContentFiltering -id $id -ContentFilteringRules $cfr } <# .SYNOPSIS Remove allowed and blocked URL patterns. .DESCRIPTION Removes the provided allowed and blocked URL patterns to the content filtering rule. .PARAMETER id The Network Id. .PARAMETER allowedURLPatterns Allowed URL patterns to remove. .PARAMETER blockedURLPatterns Blocked URL patterns to remove. .OUTPUTS The updated content filtering rules. .EXAMPLE Remove sites from the allowed and blocked URL patterns. PS> $Network | Remove-MerakiNetworkApplianceContentFilteringRule -allowedUrlPatterns "xtz.com" -blockedUrlPatterns "badsite.com" #> } set-Alias -Name RemoveMNetAppCfr -Value Remove-MerakiNetworkApplianceContentFilteringRules -Option ReadOnly function Get-MerakiAppliancePorts() { [cmdletbinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id ) Begin { $Headers = Get-Headers } Process { $Uri = "{0}/networks/{1}/appliance/ports" -f $BaseURI, $id try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response }catch { throw $_ } } <# .SYNOPSIS Returns the port copnfiguration for the Network Appliance. .PARAMETER id The network Id. .OUTPUTS An array of Meraki port objects. #> } Set-Alias -Name GMAppPorts -value Get-MerakiAppliancePorts -Option ReadOnly function Get-MerakiNetworkApplianceStaticRoutes() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id ) $uri = "{0}/networks/{1}/appliance/staticRoutes" -f $BaseURI, $id $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Returns the stauc routes for this network appliance. .PARAMETER id The Network Id. .OUTPUTS An array of Meraki static route objects. #> } Set-Alias -Name GMNetAppRoutes -Value Get-MerakiNetworkApplianceStaticRoutes -Option ReadOnly #region VLANs function Get-MerakiNetworkApplianceVLANS() { [cmdletbinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$id ) Begin { $Headers = Get-Headers } Process { $Uri = "{0}/networks/{1}/appliance/vlans" -f $BaseURI, $id try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } } <# .SYNOPSIS Returns the VLANs for the network appliance. .PARAMETER id The network Id. .OUTPUTS AN array of Meraki VLAN objects. #> } Set-Alias -Name GMNetAppVLANs -Value Get-MerakiNetworkApplianceVLANS -Option ReadOnly function Get-MerakiNetworkApplianceVLAN() { [cmdletbinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String]$networkId, [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$id ) $Uri = "{0}/networks/{1}/appliance/vlans/{2}" -f $BaseURI, $networkId, $id $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Returns a network appliance VLAN .PARAMETER networkId The Network Id. .PARAMETER id The VLAN Id. .OUTPUTS A Meraki VLAN object. #> } Set-Alias -name GMNetAppVLAN -Value Get-MerakiNetworkApplianceVLAN -Option ReadOnly function Add-MerakiNetworkApplianceVlan() { Param( [Parameter(Mandatory = $true)] [string]$NetworkId, [Parameter(Mandatory = $true)] [string]$VlanId, [Parameter(Mandatory = $true)] [string]$Name, [string]$Subnet, [string]$ApplianceIp, [string]$GroupPolicyId, [ValidateSet('same','unique')] [string]$TemplateVlanType, [string]$CIDR, [int]$Mask, [switch]$Ipv6Enabled, [hashtable]$Ipv6PrefixAssignments, [switch]$MandatoryDHCP ) $Headers = Get-Headers $Uri = "{0}/networks/{1}/appliance/vlans" -f $BaseURI, $NetworkId $_Body = @{ "id" = $VlanId "name" = $Name } if ($Subnet) { $_Body.Add("subnet", $Subnet) } if ($ApplianceIp) { $_Body.Add("applianceIp", $ApplianceIp) } if ($GroupPolicyId) { $_Body.Add("groupPolicyId", $GroupPolicyId) } if ($TemplateVlanType) { $_Body.Add("templateVlanType", $TemplateVlanType) } if ($CIDR) { $_Body.Add("cidr", $CIDR) } if ($Mask) { $_Body.Add("mask", $Mask ) } if ($Ipv6Enabled.IsPresent) { $_Body.Add("ipv6", @{ "enabled" = $true "PrefixAssignments" = $Ipv6PrefixAssignments }) } if ($MandatoryDHCP.IsPresent) { $_Body.Add( @{ "enabled" = $true } ) } $body = $_Body | ConvertTo-Json -Depth 5 -Compress try { $response = Invoke-RestMethod -Method POST -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } } Function Remove-MerakiNetworkApplianceVlan() { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Mandatory = $true)] [string]$NetworkId, [Parameter(Mandatory)] [string]$VlanId ) $Headers = Get-Headers $Uri = "{0}/networks/{1}/appliance/vlans/{2}" -f $BaseURI, $NetworkId, $VlanId if ($PSCmdlet.ShouldProcess("Delete", "VLAN ID $VlanId")) { try { $response = Invoke-RestMethod -Method DELETE -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } } <# .SYNOPSIS Remove a VLAN .DESCRIPTION Remove a Meraki Appliance VLAN .PARAMETER NetworkId The Id of the network .PARAMETER VlanId The VLAN ID to remove #> } function Set-MerakiNetworkApplianceVLAN() { [CmdletBinding()] Param( [Parameter( Mandatory = $true )] [Alias("NetworkId")] [string]$id, [Parameter(Mandatory = $true)] [string]$VlanId, [string]$VlanName, [String]$ApplianceIp, [string]$Subnet, [string]$GroupPolicyId, [ValidateSet("same","unique")] [string]$TemplateVlanType, [string]$TranslateVPNSubnet, [string]$CIDR, [string]$Mask, [ValidateScript({$_ -is [hashtable]})] [hashtable]$fixedIpAssignments, [hashtable[]]$ReservedIpRanges, [string]$DnsNameServers, [ValidateSet("Run a DHCP Server","Relay DHCP to another Server","Do not respond to DHCP requests")] [string]$DhcpHandling, [ValidateScript({$_ -and ($DhcpHandling -eq 'Relay DHCP to another Server"')}, ErrorMessage = "Parameter DhcpRelayServers is not valid when parameter DhcpHandling is 'Relay DHCP to another Server'")] [string[]]$DhcpRelayServerIPs, [ValidateSet( '30 minutes', '1 hour', '4 hours', '12 hours', '1 day', '1 week' )] [string]$DhcpLeaseTime, [bool]$DhcpBootOptionEnabled, [string]$DhcpBootNextServer, [string]$DhcpBootFilename, [hashtable]$DhcpOptions, [hashtable]$IPv6, [bool]$MandatoryDhcp, [string]$VpnNatSubnet ) $Headers = Get-Headers # Return the network Info so we can determine is thi snetwork is assinged to a template. $Network = Get-MerakiNetwork -networkID $id # check for Template only parameters. if ($mask -or $CIDR -or $TemplateVlanType) { if ($Network.$_isBoundToConfigTemplate -eq $false) { Throw "Parameters 'mask', 'CIDR' and TemplateVLanType are only applicable to template networks." } } $Uri = "{0}/networks/{1}/appliance/vlans/{2}" -f $BaseURI, $id, $VlanId $_body = @{} if ($name) { $_.Body.Add("name", $Name) } if ($ApplianceIp) { $_body.Add("applianceIp", $ApplianceIp) } if ($subnet) { $_body.Add("subnet", $subnet) } if ($GroupPolicyId) { $_body.Add("groupPolicyId", $GroupPolicyId) } if ($TemplateVlanType) { $_body.Add("templateVlanType", $TemplateVlanType) } if ($CIDR) { $_body.Add("cidr", $CIDR) } if ($Mask) { $_body.Add("mask", $Mask) } if ($fixedIpAssignments) { $_body.Add("fixedIpAssignments", $fixedIpAssignments) } if ($ReservedIpRanges) { $_body.Add("ReservedIpRanges", $ReservedIpRanges) } if ($DnsNameServers) { $_body.Add("dnsNameservers", $DnsNameServers) } if ($DhcpHandling) { $_body.Add("dhcpHandling", $DhcpHandling) } if ($DhcpRelayServerIPs) { $_body.Add("dhcpRelayServerIps", $DhcpRelayServerIPs) } if ($DhcpLeaseTime) { $_body.Add("dhcpLeaseTime", $DhcpLeaseTime) } if ($DhcpBootOptionEnabled) { $_body.Add("dhcpBootOptionsEnabled", $DhcpBootOptionEnabled) } if ($DhcpBootNextServer) { $_body.Add("dhcpBootNextServer", $DhcpBootNextServer) } if ($DhcpBootFilename) { $_body.Add("dhcpBoofFilename", $DhcpBootFilename) } if ($IPv6) { $_body.Add("ipv6", $IPv6) } if ($MandatoryDhcp) { $_body.Add("mandatoryDhcp", $MandatoryDhcp) } if ($VpnNatSubnet) { $_body.Add("vpnNatSubnet", $VpnNatSubnet) } $body = $_body | ConvertTo-Json -Depth 10 -Compress Try { $response = Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response } catch { Throw $_ } <# .SYNOPSIS "Update Appliance VLAN" .DESCRIPTION "Updates settings for a Meraki Appliance VLAN" .PARAMETER id "Network Id" .PARAMETER VlanId "VLAN ID to be updated" .PARAMETER VlanName "Name of the VLAN" .PARAMETER ApplianceIp "Appliance IP for this VLAN (Default Gateway)" .PARAMETER Subnet "Subnet for this VLAN" .PARAMETER GroupPolicyId .ID of the group policy to apply to this VLAN" .PARAMETER TemplateVlanType "Type of subnetting of the VLAN. Applicable only for template network" .PARAMETER TranslateVPNSubnet #> } Set-Alias -Name SetMNAppVLAN -Value Set-MerakiNetworkApplianceVLAN #endregion function Get-MerakiNetworkApplianceSiteToSiteVPN() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id, [switch]$hr ) $Uri = "{0}/networks/{1}/appliance/vpn/siteToSiteVpn" -f $BaseURI, $id $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect if ($hr) { $heading = [pscustomobject][ordered]@{ network = (Get-MerakiNetwork -networkID $id).name mode = $response.mode } Write-Output $heading | Format-List Write-Output "Hubs:" if ($response.mode = "spoke") { $hubs = @() $response.hubs | ForEach-Object { $Hub = [PSCustomObject][ordered]@{ Name = (Get-MerakiNetwork -networkID $_.HubId).name DefaultRoute = $_.useDefaultRoute } $Hubs += $Hub } Write-Output $hubs | Format-Table } Write-Output "Subnets:" $subnets = @() $response.subnets | ForEach-Object { $subnet = [PSCustomObject][ordered]@{ localSubnet = $_.localSubnet useVpn = $_.useVpn } $subnets += $subnet } Write-Output $subnets | Format-Table } else { return $response } } catch { throw $_ } <# .SYNOPSIS Returns a Meraki Network appliance Site-to-Site VPN configuration. .PARAMETER id The network Id. .PARAMETER hr Formats the output into 2 tables. Hubs and Subnets. .OUTPUTS If -hr is specified outputs tables to the console. If -hr is omitted, outputs a Meraki Site-to-Site VPN object. #> } Set-Alias -Name GMNetAppSSVpn -Value Get-MerakiNetworkApplianceSiteToSiteVPN -Option ReadOnly function Set-MerakiNetworkApplianceSiteToSiteVpn() { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [string]$NetworkId, [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [ValidateSet('none', 'spoke', 'hub')] [string]$Mode, [Parameter(ValueFromPipelineByPropertyName)] [psobject[]]$Hubs, [Parameter(ValueFromPipelineByPropertyName)] [psobject[]]$Subnets ) $Headers = Get-Headers $Uri = "{0}/networks/{1}/appliance/vpn/siteToSiteVpn" -f $BaseURI, $NetworkId If ($VpnSettings) { $body = $VpnSettings | ConvertTo-Json -Depth 6 -Compress } else { $_Body = @{ mode = $mode } if ($Hubs) { foreach ($Hub in $hubs) { if (-not $Hub.hubid) { throw "Property hubId is required for all Hubs" } } $_Body.Add("hubs", $Hubs) } if ($Subnets) { foreach($Subnet in $Subnets) { if (-not $Subnet.localSubnet) { throw "Property localSubnet is requored for all Subnets" } } $_Body.Add("subnets", $Subnets) } $body = $_Body | ConvertTo-Json -Depth 6 -Compress } try { $response = Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body $Body -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } <# .SYNOPSIS Update Network Site-to-Site VPN .DESCRIPTION Update the Meraki Network Site to Site VPN Settings. .PARAMETER NetworkId The ID of the to update .PARAMETER VpnSettings A Object containing the VPN Settings to apply. This parameter must be used without other parameters. .PARAMETER Mode The site-to-site VPN mode. Can be one of 'none', 'spoke' or 'hub' .PARAMETER Hubs The list of VPN hubs, in order of preference. In spoke mode, at least 1 hub is required. Hub objects contain the following properties. hubId:string (Required) - The network ID of the hub. useDefaultRoute:boolean - Only valid in 'spoke' mode. Indicates whether default route traffic should be sent to this hub. .PARAMETER Subnets The list of subnets and their VPN presence. Subnet object contain the following properties: localSubnet:string (required) - The CIDR notation subnet used within the VPN useVpn: boolean - Indicates the presence of the subnet in the VPN .EXAMPLE Updating an existing network configured as a spoke. # The easiest way to do this is to get the current von settings in an object. $VpnSettings = Get-MerakiNetworkApplianceSiteToSiteCpn -id N_1246598574 # Modify the settings in this object # Set the 1st hub destination $VpnSettings.hubs[0].hubId = N_5452659857 $VpnSettings.hubs[0].useDefaultRoute = $false # Modify the 2nd hub destination $VpnSettings.hubs[0].hubId = N_4585965254 $VpnSettings.hubs[0].useDefaultRoute = $false # Modify the subnet settings if necessary $VpnSettings.Subnets[0].localSubnet = 10.5.5.5/24 $VpnSettings.Subnets[0].useVpn = $true # Update the VPN Settings Set-MeraqkiNetworkApplianceSiteToSiteVpn -NetworkId N_1246598574 -VpnSettings $VpnSettings .EXAMPLE In this example we are going to convert a Hub (mess) network to a Spoke network In this instance the subnet is already set as we want it so we will only change the mode and add in the remote hub networks. # Create an array of hubs object $Hubs = @( @{ hubId = "N_54265629254" useDefaultRoute = $False }, @{ hubId = "N_75485962345" useDefaultroute = $false } ) Set-MerakiNetworkApplianceSiteToSiteVpn -NetworkId N_845926352 -Mode Spoke -Hubs $Hubs #> } function Get-MerakiApplianceUplinkStatuses() { [CmdletBinding()] Param( [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [String]$networkId="*", [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [String]$serial="*", [string]$profileName ) $config = Read-Config if ($profileName) { $OrgID = $config.profiles.$profileName if (-not $orgId) { throw "invalid profile name!" } } else { $OrgID = $config.profiles.default } $Uri = "{0}/organizations/{1}/appliance/uplink/statuses" -f $BaseURI, $OrgID $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect return $response | Where-Object {$_.networkID -like $networkID -and $_.serial -like $serial} } catch { throw $_ } <# .SYNOPSIS Returns the Uplink status of Meraki Networks. .PARAMETER networkId Filters the output by network Id. .PARAMETER serial Filters the output by Appliance serial number. .PARAMETER profileName Returns uplink status for appliances in this profile. if omitted uses the default profile. .OUTPUTS An array of Meraki uplink objects. #> } Set-Alias -Name GMAppUpStat -value Get-MerakiApplianceUplinkStatuses -Option ReadOnly function Get-MerakiNetworkApplianceVpnStats() { [cmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string]$id, [ValidateSet({$_ -is [int]})] [int]$perPage=100, [ValidateSet({$_ -is [int]})] [int]$timespan=5, [switch]$Sumarize, [string]$profileName ) Begin { $Headers = Get-Headers $config = read-config if ($profileName) { $OrgID = $config.profiles.$profileName if (-not $OrgId) { throw "Invalid profile name!" } } else { $OrgID = $config.profiles.default } class vpnPeer { [string]$networkID [string]$networkName [string]$peerNetworkId [string]$peerNetworkName [int]$receivedKilobytes [int]$sentKilobytes } class summaryVpnPeer { [string]$networkID [string]$networkName [int]$totalReceivedKilobytes [int]$totalSentKilobytes } } Process { $Network = Get-MerakiNetwork -networkID $id $Uri = "{0}/organizations/{1}/appliance/vpn/stats" -f $BaseURI, $OrgID $TimeSpan_Seconds = (New-TimeSpan -Days $timespan).TotalSeconds $Uri = "{0}?perPage={1}&networkIds%5B%5D={2}×pan={3}" -f $Uri, $timespan, $id, $TimeSpan_Seconds try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect $peers = $response.merakiVpnPeers $PeerNetworks = New-object System.Collections.Generic.List[psobject] foreach ($peer in $peers) { $P = [vpnPeer]::New() $P.networkID = $id $P.networkName = $Network.name $P.peerNetworkId = $peer.networkId $P.peerNetworkName = $peer.networkName $P.receivedKilobytes = $peer.usageSummary.receivedInKilobytes $P.sentKiloBytes = $peer.usageSummary.sentInKilobytes $PeerNetworks.Add($P) } $vpnPeers = $PeerNetworks.ToArray() if ($Sumarize) { $summary = [summaryVpnPeer]::New() $summary.networkID = $id $Summary.networkName = $Network.name $summary.totalReceivedKilobytes = ($vpnPeers | Measure-Object -Property receivedKilobytes -Sum).Sum $summary.totalSentKilobytes = ($vpnPeers | Measure-Object -Property sentKilobytes -Sum).Sum return $summary } else { $vpnPeers } } catch { throw $_ } } <# .SYNOPSIS Returns VPN statistics for the given organization network. .PARAMETER id The Network Id. .PARAMETER perPage The number of entries per page returned. Acceptable range is 3 - 300. Default is 300. .PARAMETER timespan Number of seconds to return data for. default = 5. .PARAMETER Sumarize Summerize the statistics, .PARAMETER profileName Return statistics for this profile. Note: The network ID must exist in this organization. .OUTPUTS AN array op VPN peer objects or a summary object. #> } Set-Alias -Name GMAVpnStats -Value Get-MerakiNetworkApplianceVpnStats -Option ReadOnly function Get-MerakiNetworkApplianceDhcpSubnets() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [string]$serial ) Begin { $Headers = Get-Headers } Process { $Url = "{0}/devices/{1}/appliance/dhcp/subnets" -f $BaseURI, $Serial try { $response = Invoke-RestMethod -Method GET -Uri $Url -Headers $Headers -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } } <# .SYNOPSIS Returns DHCP Subnets for an appliance. .DESCRIPTION Returns inforation and statistics for an appliances DHCP subnets. Including used count and free count. .PARAMETER serial The serial number of the appliance. .OUTPUTS A collection of Subnet objects. #> } Set-Alias -Name GMNetAppDhcpSubnet -Value Get-MerakiNetworkApplianceDhcpSubnets -Option ReadOnly #region Firewall function Get-MerakiNetworkApplianceCellularFirewallRules () { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [Alias('NetworkId')] [string]$Id ) Begin { $Headers = Get-Headers $Uri = "{0}/network/{1}/appliance/firewall/cellularFirewallRules" -f $BaseURI, $Id } Process { $Network = Get-MerakiNetwork -networkID $Id try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect $response | Add-Member -MemberType NoteProperty -Name "NetworkId" -Value $Id $response | Add-Member -MemberType NoteProperty -Name "NetworkName" -Value $Network.Name return $response } catch { throw $_ } } } function Set-MerakiNetworkApplianceCellularFirewallRules() { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [Alias('NetworkId')] [string]$Id, [Parameter(Mandatory = $true)] [psObject[]]$Rules ) $Headers = Get-Headers $Uri = "{0}/networks/{1}/appliance/firewall/cellularFirewallRules" -f $BaseURI, $Id $body = $Rules | ConvertTo-Json -Depth 4 -Compress try { $response = Invoke-RestMethod -Method Put -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response } catch { throw $_ } } function Set-MerakiNetworkApplianceCellularFirewallRule() { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [Alias('Networkid')] [string]$Id, [Parameter(Mandatory = $true)] [int]$RuleIndex, [Parameter(Mandatory = $true)] [ValidateSet('allow','deny')] [string]$Policy, [Parameter(Mandatory = $true)] [ValidateSet('tcp', 'udp', 'icmp', 'icmp6', 'any')] [string]$protocol, [Alias('srcPort')] [string]$SourcePort = 'any', [Parameter(Mandatory = $true)] [ALias('srcCidr')] [string]$SourceCidr, [Parameter(Mandatory = $true)] [Alias('DestCidr')] [string]$DestinationCidr, [Alias('destPort')] [string]$DestinationPort = 'any', [switch]$SyslogEnabled, [Parameter(Mandatory = $true)] [string]$Comment ) $rules = (Get-MerakiNetworkApplianceCellularFirewallRules -id $Id).rules $alRules = [System.Collections.ArrayList]$rules $alRules.RemoveAt($RuleIndex) $Properties = [PSCustomObject]@{ "policy" = $Policy "srcCidr" = $SourceCidr "srcPort" = $SourcePort "protocol" = $protocol "destCidr" = $DestinationCidr "destPort" = $DestinationPort "comment" = $Comment } if ($SyslogEnabled.IsPresent) { $properties.Add("syslogEnabled", $SyslogEnabled) } $rule = [PSCustomObject]$Properties $alRules.Insert($RuleIndex, $rule) $newRules = $alRules.ToArray() try { $response = Set-MerakiNetworkApplianceCellularFirewallRules -Id $NetworkId, -rules $newRules return $response } catch { throw $_ } } function Add-MerakiNetworkApplianceCellularFirewallRule() { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [Alias('Networkid')] [string]$Id, [Parameter(Mandatory = $true)] [ValidateSet('allow','deny')] [string]$Policy, [Parameter(Mandatory = $true)] [ValidateSet('tcp', 'udp', 'icmp', 'icmp6', 'any')] [string]$protocol, [Alias('srcPort')] [string]$SourcePort = 'any', [Parameter(Mandatory = $true)] [ALias('srcCidr')] [string]$SourceCidr, [Parameter(Mandatory = $true)] [Alias('DestCidr')] [string]$DestinationCidr, [Alias('destPort')] [string]$DestinationPort = 'any', [switch]$SyslogEnabled, [Parameter(Mandatory = $true)] [string]$Comment ) $Rules = (Get-MerakiNetworkApplianceCellularFirewallRules -Id $Id).rules $Properties = [PSCustomObject]@{ "policy" = $Policy "srcCidr" = $SourceCidr "srcPort" = $SourcePort "protocol" = $protocol "destCidr" = $DestinationCidr "destPort" = $DestinationPort "comment" = $Comment } if ($SyslogEnabled.IsPresent) { $properties.Add("syslogEnabled", $SyslogEnabled) } $rule = [PSCustomObject]$Properties $Rules += $rule try { $response = Set-MerakiNetworkApplianceCellularFirewallRules -Id $id, -Rules $Rules return $response } catch { throw $_ } } function Remove-MerakiNetworkApplianceCellularFirewallRule() { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Mandatory = $true)] [string]$NetworkId, [Parameter(Mandatory = $true)] [int]$RuleIndex ) $Rules = (Get-MerakiNetworkApplianceCellularFirewallRules -id $NetworkId).Rules $alRules = [System.Collections.ArrayList]$Rules $alRules.RemoveAt($RuleIndex) $newRules = $alRules.ToArray() if ($PSCmdlet.ShouldProcess('DELETE', "Cellular Firewall Rule at index $ruleIndex")) { try { $response = Set-MerakiNetworkApplianceCellularFirewallRules -Id $NetworkId -Rules $newRules return $response } catch { throw $_ } } } #endregion #region Firewalled Services function Get-MerakiNetworkApplianceFirewalledServices() { [CmdletBinding()] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias('Networkid')] [string]$Id ) Begin { $Headers = Get-Headers } Process { $Uri = "{0}/networks/{1}/appliance/firewall/firewalledServices" -f $BaseURI, $Id $Network = Get-MerakiNetwork -networkID $Id try { $response = Invoke-RestMethod -Method Get -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect $response | Add-Member -MemberType NoteProperty -Name "NetworkId" -Value $Id $response | Add-Member -MemberType NoteProperty -Name "NetworkName" -Value $Network.Name return $response } catch { Throw $_ } } } #endregion #region L3 Firewall Rules Function Get-MerakiApplianceL3FirewallRules() { [CmdletBinding()] Param( [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [Alias('NetworkId')] [string]$id ) $Uri = "{0}/networks/{1}/appliance/firewall/l3FirewallRules" -f $BaseURI, $Id $Headers = Get-Headers try { $response = Invoke-RestMethod -Method GET -Uri $Uri -Headers $Headers -PreserveAuthorizationOnRedirect $rules = $response.Rules $ruleId = 1 $rules | Foreach-Object { $_ | Add-Member -MemberType NoteProperty -Name "RuleId" -Value $ruleId $RuleId += 1 } return $rules } catch { Throw $_ } } function Set-MerakiApplianceL3FirewallRules() { [CmdletBinding()] Param( [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [Alias('NetworkId')] [string]$Id, [Parameter( Mandatory )] [psobject[]]$Rules, [switch]$PassThru ) Begin { $Headers = Get-Headers # The below statements are used if rules are being copied from another network/ # Remove the RuleId property. This is added and used by this module and is not part of the Meraki configuration. if ($Rules[0].PSObject.Properties.Name -contains 'RuleId') { $Rules = $Rules | Select-Object -Property * -ExcludeProperty RuleId } # remove the default rule if it exists. $Rules = $Rules | Where-Object {$_.comment -ne 'Default rule'} } Process { $Uri = "{0}/networks/{1}/appliance/firewall/l3FirewallRules" -f $BaseUri, $id $_body = @{"rules" = $Rules} $body = $_body | ConvertTo-Json -Depth 5 -Compress try { $response = Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response.rules } catch { throw $_ } } } function Add-MerakiApplianceL3FirewallRule() { [CmdletBinding()] Param( [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [Alias('NetworkId')] [string]$Id, [ValidateSet('allow','deny')] [string]$Policy, [string]$Comment, [ValidateSet('tcp', 'udp', 'icmp', 'icmp6', 'any')] [string]$Protocol, [ValidateScript( { $subnetPart = $_.split("/") $_ -eq "any" -or ([IPAddress]$subnetPart[0] -is [IPAddress] -and $SubnetPart[1] -In 0..32) } )] [string]$SourceCIDR, [string]$SourcePort = 'any', [ValidateScript( { $subnetPart = $_.split("/") $_ -eq "any" -or [IPAddress]$subnetPart[0] -is [IPAddress] -and $SubnetPart[1] -In 0..32 } )] [string]$DestinationCIDR, [string]$DestinationPort = 'any', [switch]$SyslogEnabled, [switch]$PassThru ) Begin { $Headers = Get-Headers } Process { $Uri = "{0}/networks/{1}/appliance/firewall/l3FirewallRules" -f $BaseUri, $Id $Rules = Get-MerakiApplianceL3FirewallRules -id $Id | Select-Object * -ExcludeProperty RuleId # Remove the default rule $Rules = $Rules | Where-Object {$_.comment -ne "Default rule"} $NewRule = [PSCustomObject]@{ policy = $policy comment = $Comment protocol = $Protocol destPort = $DestinationPort destCidr = $DestinationCIDR srcPort = $SourcePort srcCidr = $SourceCIDR syslogEnabled = $SyslogEnabled.IsPresent } $Rules += $NewRule $_Body = @{rules = $Rules} $body = $_body | ConvertTo-JSON -Depth 5 -Compress try { $response = Invoke-RestMethod -Method Put -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response.rules } catch { throw $_ } } <# .SYNOPSIS Add a Level 3 Firewall rule. .DESCRIPTION Adds a Level 3 firewall rule to a Meraki Appliance. .PARAMETER Id The Network ID. .PARAMETER Policy The Policy for this rule. .PARAMETER Comment Description of the rule. .PARAMETER Protocol The protocol to use .PARAMETER SourceCIDR Comma-separated list of source IP address(es) (in IP or CIDR notation), or 'any' (note: FQDN not supported for source addresses) .PARAMETER SourcePort Comma-separated list of source port(s) (integer in the range 1-65535), or 'any' .PARAMETER DestinationCIDR Comma-separated list of destination IP address(es) (in IP or CIDR notation), fully-qualified domain names (FQDN) or 'any' .PARAMETER DestinationPort Comma-separated list of destination port(s) (integer in the range 1-65535), or 'any' .PARAMETER SyslogEnabled Log this rule to syslog - only applicable if a syslog has been configured (optional) .PARAMETER PassThru Return the newly created rule. #> } function Set-MerakiApplianceL3FirewallRule() { [CmdletBinding()] Param( [Parameter( Mandatory )] [string]$NetworkId, [int]$RuleId, [ValidateSet('allow','deny')] [string]$Policy, [string]$Comment, [ValidateSet('tcp', 'udp', 'icmp', 'icmp6', 'any')] [string]$Protocol, [ValidateScript( { $subnetPart = $_.split("/") [IPAddress]$subnetPart[0] -is [IPAddress] -and $SubnetPart[1] -In 0..32 } )] [string]$SourceCIDR, [string]$SourcePort, [ValidateScript( { $subnetPart = $_.split("/") [IPAddress]$subnetPart[0] -is [IPAddress] -and $SubnetPart[1] -In 0..32 } )] [string]$DestinationCIDR, [string]$DestinationPort, [switch]$SyslogEnabled ) $Uri = "{0}/networks/{1}/appliance/firewall/l3FirewallRules" -f $BaseUri, $NetworkId $Headers = Get-Headers $Rules = Get-MerakiApplianceL3FirewallRules -id $NetworkId # Remove the Default Rule $Rules = $Rules | Where-Object {$_.comment -ne "Default rule"} $Rule = $Rules | Where-Object {$_.RuleId -eq $RuleId} if (-not $Rule) { throw "Invalid Rule Id" } $Rules = $Rules | Where-Object {$_.RuleId -ne $RuleId} If ($Policy) {$Rule.policy = $Policy} if ($Comment) {$Rule.comment = $Comment} if ($Protocol) {$Rule.protocol = $Protocol} if ($SourceCIDR) {$Rule.srcCIDR - $SourceCIDR} if ($SourcePort) { $Rule.srcPort = $SourcePort} if ($DestinationCIDR) {$Rule.destCIDR = $DestinationCIDR} if ($DestinationPort) {$Rule.destPort = $DestinationPort} if ($SyslogEnabled) {$Rule.syslogEnabled = $SyslogEnabled} $Rules += $Rule # Remove the RuleId Property $newRules = $Rules | Select-Object * -ExcludeProperty RuleId $_Body = @{rules = $newRules} $body = $_Body | ConvertTo-Json try { $response = Invoke-RestMethod -Method PUT -Uri $uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response.rules } catch { throw $_ } <# .SYNOPSIS Update an existing level 3 firewall rule. .DESCRIPTION Update an existing Level 3 firewall rule on a meraki Appliance. .PARAMETER #> } function Remove-MerakiApplianceL3FirewallRule() { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter( Mandatory )] [string]$NetworkId, [Parameter(Mandatory)] [string]$RuleId, [switch]$PassThru ) $Uri = "{0}/networks/{1}/appliance/firewall/l3FirewallRules" -f $BaseUri, $NetworkId $Headers = Get-Headers $Rules = Get-MerakiApplianceL3FirewallRules -id $NetworkId # Remove the Default Rule $Rules = $Rules | Where-Object {$_.comment -ne "Default rule"} $Rule = $Rules | Where-Object {$_.RuleId -eq $RuleId} if (-not $Rule) { throw "Invalid Rule Id" } # Remove the Rule to be deleted $Rules = $Rules | Where-Object {$_.RuleId -ne $RuleId} # Remove the Rule Property $Rules = $Rules | Select-Object -Property * -ExcludeProperty RuleId $_Body = @{rules = $Rules} $body = $_Body | ConvertTo-Json -Depth 5 -Compress if ($PSCmdlet.ShouldProcess("Delete","Rule:$($Rule.Comment)")) { try { $response = Invoke-RestMethod -Method PUT -Uri $Uri -Headers $Headers -Body $body -PreserveAuthorizationOnRedirect return $response.rules } catch { throw $_ } } } #endregion |