change wifi password script failing after update

Solved
werowance
Conversationalist

change wifi password script failing after update

since the latest update my pieced together script that i put to gether using other peoples scripts has stopped working.  i have tried and tried to figure out what is wrong and also tried switching to v1 api but no luck,  below is a sanitized copy of my script and was really really hoping someone could help.  it changes the wifi password on a scheduled basis for guest wifi.   any help is very much appreciated.

 

param([string]$site="",[string]$ssid="",[string]$action="")
 
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11
  
 
 
 
 
 
 
# change path below for password file name
 
 
$chgpw = get-content "C:\Users\removedusernameforsecurity\Desktop\update meraki wifi passwords\password.txt"
 
 
 
 
 
 
 
 
 
function updateWiFiPSK ([string]$s_id, [string]$w_id, [string]$chgpw)
{
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
 
# PSK = New password
$data = @{
"psk" = $chgpw
}
 
#Convert data to Json format
$jbody = ConvertTo-Json -InputObject $data
 
#Combine base URL and ssid
$request_uri = $base_uri + $networks_uri + $s_id + "/ssids/" + $w_id
 
$r = Invoke-WebRequest $request_uri -Method:Put -Headers $header_org -Body $jbody
 
return $r
}
 
function Get-SiteID
    {
    #get site id
    $request_uri = $base_uri + $networks_uri
    $r = Invoke-WebRequest $request_uri -Method:Get -Headers $header_org
 
    $json = $r | ConvertFrom-Json
    for($i=0;$i -lt $json.count;$i++)
        {
        if ($site -eq $json[$i].name)
            {
        
 
            $s_id = $json[$i].id
            }
        }
 
    return $s_id
    }
 
function Get-WiFiSSID ([string]$s_id)
    {
    #get wifi network ID from site requested
    if ($s_id -ne "")
        {
        $request_uri = $base_uri + $networks_uri + $s_id + "/ssids/"
        $r = Invoke-WebRequest $request_uri -Method:Get -Headers @{"X-Cisco-Meraki-API-Key"="removedkeyforsecuritytopostonline"} -ContentType "application/json"
 
        $z = $r | ConvertFrom-Json
 
        for($i=0;$i -lt $z.count;$i++)
            {
          
            If ($z[$i].name -eq $ssid)
                {
               
                write-output $z[$i].psk > c:\trash.txt
                $w_id = $z[$i].number
                }
            }
        }
 
    return $w_id
    }
 
 
 
# setup some global static stuff
##    E.G.   n34.meraki.com/api/v0/organizations/<OrgID>/
$networks_uri = "networks/"
#Meraki API KEY
$api_key = "keyeditedforsecurity"
$header_org = @{"X-Cisco-Meraki-API-KEY" = $api_key;"Content-Type" = 'application/json'}
 
$s_id = ""
$w_id = ""
$mode = ""
 
If ($site -eq "" -or $ssid -eq "")
    {
    Write-Host "MerakiPSKTool - (c) 2019"
    Write-Host ""
    Write-Host "Site/SSID parameter is missing"
    Write-Host "Usage: MerakiPSKTool.ps1 -site <sitename> -ssid <ssidName> -action [Change | Display]"
    Write-Host ""
    
    exit
    } 
 
# if action not passed or is blank, set default mode to Display
if ($action -eq "")
    {
    $action = "Display"
    }
 
switch ($action)
    {
    {@("Display", "display") -contains $_ }
        {
            "Displaying Wifi details"
            $mode = "display"
        }
    
    {@("Change", "change") -contains $_ }
        {
            
            $mode = "change"
        }
 
    default { "MerakiPSKTool.ps1" }
    }
 
 
# get ID of the site passed in params (set a default value if no site passed)
$s_id = Get-SiteID
 
If ($s_id -ne "")
    {
    # get id of Wifi network that password is to be changed for
    $w_id = Get-WifiSSID($s_id)
 
    #Write-Host "Site ID      : " $s_id " | Wifi #: " $w_id
    } 
 
if ($mode -eq "change")
    {
  
 
    $result = updateWiFiPSK $s_id $w_id $chgpw
 
  
 
    
 
        }
    else
        {
        Write-Host "Password change failed for " + $ssid + " at " + $site
        }
   
1 Accepted Solution
gful
Conversationalist

I came across this post as I was working on my own very similar issue.  This is what worked for me if it's of any help. 

 

Skipping ahead to after the realization the script was not working, I ran it manually and the error I received was along the lines of invalid URL.  Seemed like a good place to start.

 

The URL from my old script that was being passed:

   h t t p s://n###.meraki.com/api/v0/organizations/#####/networks/NETWORK_ID/wireless/ssids/4

 

I found another post on the forums:

https://community.meraki.com/t5/Developers-APIs/Meraki-API-amp-Powershell-Script-issues/m-p/195917

that got me to the URL that worked:

     h t t p s://n###.meraki.com/api/v1/networks/NETWORK_ID/wireless/ssids/4

 

I also changed all references of v0 to v1 in the other areas of the script.

 

 

View solution in original post

16 Replies 16
alemabrahao
Kind of a big deal
Kind of a big deal

Have you tried asking Chatgpt to find the sript error?
 
It's no joke, I've already done some tests and sometimes it saves lives. Of course, remember not to leave confidential information in the script.
I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
sungod
Head in the Cloud

It's well over a year since sunset on the v0 API...

https://community.meraki.com/t5/Developers-APIs/Dashboard-API-v0-End-of-Support-Sunset-amp-Grace-Per...

 

Irrespective of the problem, you really do need to move to v1.

 

The v0 / v1 calls may not work exactly the same, I suggest make a simplified script to test using v1.

 

Also, you don't say what (if any) error messages you are getting, it might help figure out the issue if you gave the details.

 

werowance
Conversationalist

well im not smart enough to migrate it v1, i tried editing the url with v1 but as you said the calls probably are not exactly the same.

 

and on chat gpt,  no i have never tried that.   was really hoping someone could point out something like they increased tls security to something higher that 1.2 or similar or you could spot a simple minor change needed

Try this function.

 

 

$r = Invoke-WebRequest $request_uri -Method Put -Headers $header_org -Body $jbody

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.
PhilipDAth
Kind of a big deal
Kind of a big deal

Give us a hint.  What error do you get when using the v1 API?

werowance
Conversationalist

unfortunately that didnt work,  but the error im getting is the page doesnt exist.   and after some more research i think i can get it fixed if i knew the following info

 

in the documentation it says the url should be:

https://api.meraki.com/api/v0/networks/{{networkId}}/ssids/  for version 0 and for version 1 it should be

https://api.meraki.com/api/v1/networks/{{networkId}}/wireless/ssids/

for testing i do this

 


https://nxxx.meraki.com/api/v1/organizations/xxxxxx/networks/L_xxxxxxxxxxx/wireless/ssids and this fails. now if i back space off the wireless/ssids and i get some good data.  of course the above is also sanitized a bit.

so if someone could tell me what would come after /networks/L_xxxxxxxx in a web browser to see the data then i should be able to modify the script accordingly.  i hope that make sense

It's the network ID. You can get it with this API.

 

https://developer.cisco.com/meraki/api/get-network/

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.

i have the network id   thats the L_xxxxxxxxxxx in my string above.  yes that is sanitized but i had it

guess what i am saying is that Meraki has removed /ssids as well as /networks/ssids from their urls.  even the v1 code samples to just query all ssid names inside postman dont work anymore.  they all return a web page back "page not found" with a meraki logo on it.  

Have you checked this one?

 

https://developer.cisco.com/meraki/api-v1/update-network-wireless-ssid/

I am not a Cisco Meraki employee. My suggestions are based on documentation of Meraki best practices and day-to-day experience.

Please, if this post was useful, leave your kudos and mark it as solved.

This endpoint? https://developer.cisco.com/meraki/api-v1/get-network-wireless-ssids/

 

https://api.meraki.com/api/v1/networks/L_xxxxxxxxxxx/wireless/ssids works fine for me. Same with the call in Postman.

well,  other than API access which i definately have on and this was working,  is there something else that has to be turned on?  maybe some new security setting that just happened over the weekend?  ill probably open a ticket with Meraki today since you can confirm it working on your site

gful
Conversationalist

I came across this post as I was working on my own very similar issue.  This is what worked for me if it's of any help. 

 

Skipping ahead to after the realization the script was not working, I ran it manually and the error I received was along the lines of invalid URL.  Seemed like a good place to start.

 

The URL from my old script that was being passed:

   h t t p s://n###.meraki.com/api/v0/organizations/#####/networks/NETWORK_ID/wireless/ssids/4

 

I found another post on the forums:

https://community.meraki.com/t5/Developers-APIs/Meraki-API-amp-Powershell-Script-issues/m-p/195917

that got me to the URL that worked:

     h t t p s://n###.meraki.com/api/v1/networks/NETWORK_ID/wireless/ssids/4

 

I also changed all references of v0 to v1 in the other areas of the script.

 

 

werowance
Conversationalist

so yes this really helps.  but question,  if you dont include the site id in the string and you are not currently logged into the portal then how would the script actually identify whos site its working on?  does the api key tell meraki who's site it is some how?

werowance
Conversationalist

that did the trick,  modified my script $baseurl= https://n###.meraki.com/api/v1/organizations/#####/

 

then added a $baseurl2=https://n###.meraki.com/api/v1/

 

then in my script where the string included the baseurl to query the ssid i had to change it to baseurl2 as well as add in /networks/ssids/

 

long story short,  you cant query the ssid name when you have the org id in the url path.  but you cant query the network id if you dont have the org id in the path.   so the parts that query ssid name i had to use $baseurl2 and then the parts that needed to get the network name i had to use $baseurl .    then in v1 you have to have /networks/ssid/  insteadl of just /ssids/ in the path

Jhu23
Comes here often

For anyone still looking for help on this - I have mashed together the solutions provided by nealgs and by werowance. Sanitised version below. This will scramble the password and send an email as nealgs's did previously.

param([string]$site="",[string]$ssid="",[string]$action="")
 
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11

#Email settings. Copied from old v0 script.
 function sendMail([string]$txtbody)
	{
     #SMTP server name
     $smtpServer = "add your o365 mail server (domainame.mail.protection.outlook.com)"

     #Creating a Mail object
     $msg = new-object Net.Mail.MailMessage

     #Creating SMTP server object
     $smtp = new-object Net.Mail.SmtpClient($smtpServer)

     #Email structure 
     $msg.From = "enter your FROM address"
     $msg.Bcc.Add("enter your BCC address")
     $msg.To.Add("enter your TO address")
     $msg.subject = "enter your SUBJECT" 
     $msg.body = $txtbody
	 $msg.IsBodyHTML=$true

     #Sending email 
     $smtp.Send($msg)
	}


#Create a random password for the SSID. Copied from old v0 script.
function Get-RandomCharacters($length, $characters)
	{ 
    $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length } 
    $private:ofs="" 
    return [String]$characters[$random]
	}

function Scramble-String([string]$inputString)
	{     
    $characterArray = $inputString.ToCharArray()   
    $scrambledStringArray = $characterArray | Get-Random -Count $characterArray.Length     
    $outputString = -join $scrambledStringArray
    return $outputString 
	}


function updateWiFiPSK ([string]$s_id, [string]$w_id, [string]$newpassword)
{
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
 
# PSK = New password
$data = @{
"psk" = $newpassword
}
 
#Convert data to Json format
$jbody = ConvertTo-Json -InputObject $data
 
#Combine base URL and ssid
$request_uri = $base_uri2 + $networks_uri + $s_id + "/wireless/ssids/" + $w_id
 
$r = Invoke-WebRequest $request_uri -Method:Put -Headers $header_org -Body $jbody
 
return $r
}
 
function Get-SiteID
    {
    #get site id
    $request_uri = $base_uri + $networks_uri
    $r = Invoke-WebRequest $request_uri -Method:Get -Headers $header_org
 
    $json = $r | ConvertFrom-Json
    for($i=0;$i -lt $json.count;$i++)
        {
        if ($site -eq $json[$i].name)
            {
            #Copied the next 3 lines from old v0 script
            Write-host "Network Name : " $json[$i].name
            Write-host "id           : " $json[$i].id
            Write-host "Type         : " $json[$i].type        
 
            $s_id = $json[$i].id
            }
        }
 
    return $s_id
    }
 
function Get-WiFiSSID ([string]$s_id)
    {
    #get wifi network ID from site requested
    if ($s_id -ne "")
        {
        $request_uri = $base_uri2 + $networks_uri + $s_id + "/wireless/ssids/"
        $r = Invoke-WebRequest $request_uri -Method:Get -Headers @{"X-Cisco-Meraki-API-Key"="ADD YOUR API KEY HERE"} -ContentType "application/json"
 
        $z = $r | ConvertFrom-Json
 
        for($i=0;$i -lt $z.count;$i++)
            {
          
            If ($z[$i].name -eq $ssid)
                {
               #Copied the next 3 lines from old v0 script
                Write-host "SSID Name    : " $z[$i].name
                Write-host "SSID#        : " $z[$i].number 
                Write-host "Current PSK  : " $z[$i].psk

                #write-output $z[$i].psk > c:\trash.txt

                $w_id = $z[$i].number
                }
            }
        }
 
    return $w_id
    }
 
#Copied from old v0 script
 function createPassword
	{
	$password = Get-RandomCharacters -length 4 -characters 'abcdefghiklmnoprstuvwxyz'
	$password += Get-RandomCharacters -length 2 -characters 'ABCDEFGHKLMNOPRSTUVWXYZ'
	$password += Get-RandomCharacters -length 2 -characters '1234567890'
	#$password += Get-RandomCharacters -length 2 -characters '!$%&()?}][{@#+'	

	#Write-Host $password
		
	return Scramble-String $password
	}
 
# setup some global static stuff
$base_uri = "ADD URI HERE"
##    E.G.   n345.meraki.com/api/v1/organizations/xxxxxx/
$base_uri2 = "ADD URI2 HERE"
##    E.G.   https://n345.meraki.com/api/v1//
$networks_uri = "networks/"
#Meraki API KEY
$api_key = "ADD API KEY HERE (This is the second time it needs to be added)"
$header_org = @{"X-Cisco-Meraki-API-KEY" = $api_key;"Content-Type" = 'application/json'}
 
$s_id = ""
$w_id = ""
$mode = ""
 
If ($site -eq "" -or $ssid -eq "")
    {
    Write-Host "MerakiPSKTool - (c) 2019"
    Write-Host ""
    Write-Host "Site/SSID parameter is missing"
    Write-Host "Usage: MerakiPSKTool.ps1 -site <sitename> -ssid <ssidName> -action [Change | Display]"
    Write-Host ""
    
    exit
    } 
 
# if action not passed or is blank, set default mode to Display
if ($action -eq "")
    {
    $action = "Display"
    }
 
switch ($action)
    {
    {@("Display", "display") -contains $_ }
        {
            "Displaying Wifi details"
            $mode = "display"
        }
    
    {@("Change", "change") -contains $_ }
        {
            
            $mode = "change"
        }
 
    default { "MerakiPSKTool.ps1" }
    }
 
 
# get ID of the site passed in params (set a default value if no site passed)
$s_id = Get-SiteID
 
If ($s_id -ne "")
    {
    # get id of Wifi network that password is to be changed for
    $w_id = Get-WifiSSID($s_id)
 
    #Write-Host "Site ID      : " $s_id " | Wifi #: " $w_id
    } 
 
if ($mode -eq "change")
    {
    # Generate a new complex password
    $newpassword = createPassword 
 
    $result = updateWiFiPSK $s_id $w_id $newpassword
 
    #Get the current date and save it as a variable
    $curDate = get-date -format "dddd dd/MM/yyyy"  
 
# build email message body and send it
    if ($result.StatusCode -eq 200)
       {
        Write-Host "Sending Email"

        $txtbody = "<html><body>"
        $txtbody = $txtbody + "The new daily password for " + $ssid + " at " + $site + " is:<br><br><b><font size=30 color=green>"
        $txtbody = $txtbody + $newpassword + "</font></b>"
        $txtbody = $txtbody + "<br><br>Here is some body text that you can change if you want."
        $txtbody = $txtbody + "<br><br>Today's date is " + $curDate + "."
        $txtbody = $txtbody + "<br><br>This is another line of body text."
        $txtbody = $txtbody + "</body></html>"

        #Write-Host $txtbody

		# send the email
        sendMail $txtbody
    
 
        }
    else
        {
        Write-Host "Password change failed for " + $ssid + " at " + $site
        }
    }
Get notified when there are additional replies to this discussion.